@akanjs/cli 2.1.1-rc.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,329 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- var __create = Object.create;
4
- var __getProtoOf = Object.getPrototypeOf;
5
- var __defProp = Object.defineProperty;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- function __accessProp(key) {
9
- return this[key];
10
- }
11
- var __toESMCache_node;
12
- var __toESMCache_esm;
13
- var __toESM = (mod, isNodeMode, target) => {
14
- var canCache = mod != null && typeof mod === "object";
15
- if (canCache) {
16
- var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
- var cached = cache.get(mod);
18
- if (cached)
19
- return cached;
20
- }
21
- target = mod != null ? __create(__getProtoOf(mod)) : {};
22
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
- for (let key of __getOwnPropNames(mod))
24
- if (!__hasOwnProp.call(to, key))
25
- __defProp(to, key, {
26
- get: __accessProp.bind(mod, key),
27
- enumerable: true
28
- });
29
- if (canCache)
30
- cache.set(mod, to);
31
- return to;
32
- };
33
- var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
3
  var __require = import.meta.require;
35
4
 
36
- // node_modules/dayjs/dayjs.min.js
37
- var require_dayjs_min = __commonJS((exports, module) => {
38
- (function(t, e) {
39
- typeof exports == "object" && typeof module != "undefined" ? module.exports = e() : typeof define == "function" && define.amd ? define(e) : (t = typeof globalThis != "undefined" ? globalThis : t || self).dayjs = e();
40
- })(exports, function() {
41
- var t = 1000, e = 60000, n = 3600000, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $2 = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(t2) {
42
- var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
43
- return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
44
- } }, m = function(t2, e2, n2) {
45
- var r2 = String(t2);
46
- return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
47
- }, v = { s: m, z: function(t2) {
48
- var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
49
- return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
50
- }, m: function t2(e2, n2) {
51
- if (e2.date() < n2.date())
52
- return -t2(n2, e2);
53
- var r2 = 12 * (n2.year() - e2.year()) + (n2.month() - e2.month()), i2 = e2.clone().add(r2, c), s2 = n2 - i2 < 0, u2 = e2.clone().add(r2 + (s2 ? -1 : 1), c);
54
- return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
55
- }, a: function(t2) {
56
- return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
57
- }, p: function(t2) {
58
- return { M: c, y: h, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: f }[t2] || String(t2 || "").toLowerCase().replace(/s$/, "");
59
- }, u: function(t2) {
60
- return t2 === undefined;
61
- } }, g = "en", D = {};
62
- D[g] = M;
63
- var p = "$isDayjsObject", S = function(t2) {
64
- return t2 instanceof _ || !(!t2 || !t2[p]);
65
- }, w = function t2(e2, n2, r2) {
66
- var i2;
67
- if (!e2)
68
- return g;
69
- if (typeof e2 == "string") {
70
- var s2 = e2.toLowerCase();
71
- D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
72
- var u2 = e2.split("-");
73
- if (!i2 && u2.length > 1)
74
- return t2(u2[0]);
75
- } else {
76
- var a2 = e2.name;
77
- D[a2] = e2, i2 = a2;
78
- }
79
- return !r2 && i2 && (g = i2), i2 || !r2 && g;
80
- }, O = function(t2, e2) {
81
- if (S(t2))
82
- return t2.clone();
83
- var n2 = typeof e2 == "object" ? e2 : {};
84
- return n2.date = t2, n2.args = arguments, new _(n2);
85
- }, b = v;
86
- b.l = w, b.i = S, b.w = function(t2, e2) {
87
- return O(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
88
- };
89
- var _ = function() {
90
- function M2(t2) {
91
- this.$L = w(t2.locale, null, true), this.parse(t2), this.$x = this.$x || t2.x || {}, this[p] = true;
92
- }
93
- var m2 = M2.prototype;
94
- return m2.parse = function(t2) {
95
- this.$d = function(t3) {
96
- var { date: e2, utc: n2 } = t3;
97
- if (e2 === null)
98
- return new Date(NaN);
99
- if (b.u(e2))
100
- return new Date;
101
- if (e2 instanceof Date)
102
- return new Date(e2);
103
- if (typeof e2 == "string" && !/Z$/i.test(e2)) {
104
- var r2 = e2.match($2);
105
- if (r2) {
106
- var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
107
- return n2 ? new Date(Date.UTC(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2)) : new Date(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2);
108
- }
109
- }
110
- return new Date(e2);
111
- }(t2), this.init();
112
- }, m2.init = function() {
113
- var t2 = this.$d;
114
- this.$y = t2.getFullYear(), this.$M = t2.getMonth(), this.$D = t2.getDate(), this.$W = t2.getDay(), this.$H = t2.getHours(), this.$m = t2.getMinutes(), this.$s = t2.getSeconds(), this.$ms = t2.getMilliseconds();
115
- }, m2.$utils = function() {
116
- return b;
117
- }, m2.isValid = function() {
118
- return !(this.$d.toString() === l);
119
- }, m2.isSame = function(t2, e2) {
120
- var n2 = O(t2);
121
- return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
122
- }, m2.isAfter = function(t2, e2) {
123
- return O(t2) < this.startOf(e2);
124
- }, m2.isBefore = function(t2, e2) {
125
- return this.endOf(e2) < O(t2);
126
- }, m2.$g = function(t2, e2, n2) {
127
- return b.u(t2) ? this[e2] : this.set(n2, t2);
128
- }, m2.unix = function() {
129
- return Math.floor(this.valueOf() / 1000);
130
- }, m2.valueOf = function() {
131
- return this.$d.getTime();
132
- }, m2.startOf = function(t2, e2) {
133
- var n2 = this, r2 = !!b.u(e2) || e2, f2 = b.p(t2), l2 = function(t3, e3) {
134
- var i2 = b.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
135
- return r2 ? i2 : i2.endOf(a);
136
- }, $3 = function(t3, e3) {
137
- return b.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
138
- }, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
139
- switch (f2) {
140
- case h:
141
- return r2 ? l2(1, 0) : l2(31, 11);
142
- case c:
143
- return r2 ? l2(1, M3) : l2(0, M3 + 1);
144
- case o:
145
- var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
146
- return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
147
- case a:
148
- case d:
149
- return $3(v2 + "Hours", 0);
150
- case u:
151
- return $3(v2 + "Minutes", 1);
152
- case s:
153
- return $3(v2 + "Seconds", 2);
154
- case i:
155
- return $3(v2 + "Milliseconds", 3);
156
- default:
157
- return this.clone();
158
- }
159
- }, m2.endOf = function(t2) {
160
- return this.startOf(t2, false);
161
- }, m2.$set = function(t2, e2) {
162
- var n2, o2 = b.p(t2), f2 = "set" + (this.$u ? "UTC" : ""), l2 = (n2 = {}, n2[a] = f2 + "Date", n2[d] = f2 + "Date", n2[c] = f2 + "Month", n2[h] = f2 + "FullYear", n2[u] = f2 + "Hours", n2[s] = f2 + "Minutes", n2[i] = f2 + "Seconds", n2[r] = f2 + "Milliseconds", n2)[o2], $3 = o2 === a ? this.$D + (e2 - this.$W) : e2;
163
- if (o2 === c || o2 === h) {
164
- var y2 = this.clone().set(d, 1);
165
- y2.$d[l2]($3), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
166
- } else
167
- l2 && this.$d[l2]($3);
168
- return this.init(), this;
169
- }, m2.set = function(t2, e2) {
170
- return this.clone().$set(t2, e2);
171
- }, m2.get = function(t2) {
172
- return this[b.p(t2)]();
173
- }, m2.add = function(r2, f2) {
174
- var d2, l2 = this;
175
- r2 = Number(r2);
176
- var $3 = b.p(f2), y2 = function(t2) {
177
- var e2 = O(l2);
178
- return b.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
179
- };
180
- if ($3 === c)
181
- return this.set(c, this.$M + r2);
182
- if ($3 === h)
183
- return this.set(h, this.$y + r2);
184
- if ($3 === a)
185
- return y2(1);
186
- if ($3 === o)
187
- return y2(7);
188
- var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$3] || 1, m3 = this.$d.getTime() + r2 * M3;
189
- return b.w(m3, this);
190
- }, m2.subtract = function(t2, e2) {
191
- return this.add(-1 * t2, e2);
192
- }, m2.format = function(t2) {
193
- var e2 = this, n2 = this.$locale();
194
- if (!this.isValid())
195
- return n2.invalidDate || l;
196
- var r2 = t2 || "YYYY-MM-DDTHH:mm:ssZ", i2 = b.z(this), s2 = this.$H, u2 = this.$m, a2 = this.$M, o2 = n2.weekdays, c2 = n2.months, f2 = n2.meridiem, h2 = function(t3, n3, i3, s3) {
197
- return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
198
- }, d2 = function(t3) {
199
- return b.s(s2 % 12 || 12, t3, "0");
200
- }, $3 = f2 || function(t3, e3, n3) {
201
- var r3 = t3 < 12 ? "AM" : "PM";
202
- return n3 ? r3.toLowerCase() : r3;
203
- };
204
- return r2.replace(y, function(t3, r3) {
205
- return r3 || function(t4) {
206
- switch (t4) {
207
- case "YY":
208
- return String(e2.$y).slice(-2);
209
- case "YYYY":
210
- return b.s(e2.$y, 4, "0");
211
- case "M":
212
- return a2 + 1;
213
- case "MM":
214
- return b.s(a2 + 1, 2, "0");
215
- case "MMM":
216
- return h2(n2.monthsShort, a2, c2, 3);
217
- case "MMMM":
218
- return h2(c2, a2);
219
- case "D":
220
- return e2.$D;
221
- case "DD":
222
- return b.s(e2.$D, 2, "0");
223
- case "d":
224
- return String(e2.$W);
225
- case "dd":
226
- return h2(n2.weekdaysMin, e2.$W, o2, 2);
227
- case "ddd":
228
- return h2(n2.weekdaysShort, e2.$W, o2, 3);
229
- case "dddd":
230
- return o2[e2.$W];
231
- case "H":
232
- return String(s2);
233
- case "HH":
234
- return b.s(s2, 2, "0");
235
- case "h":
236
- return d2(1);
237
- case "hh":
238
- return d2(2);
239
- case "a":
240
- return $3(s2, u2, true);
241
- case "A":
242
- return $3(s2, u2, false);
243
- case "m":
244
- return String(u2);
245
- case "mm":
246
- return b.s(u2, 2, "0");
247
- case "s":
248
- return String(e2.$s);
249
- case "ss":
250
- return b.s(e2.$s, 2, "0");
251
- case "SSS":
252
- return b.s(e2.$ms, 3, "0");
253
- case "Z":
254
- return i2;
255
- }
256
- return null;
257
- }(t3) || i2.replace(":", "");
258
- });
259
- }, m2.utcOffset = function() {
260
- return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
261
- }, m2.diff = function(r2, d2, l2) {
262
- var $3, y2 = this, M3 = b.p(d2), m3 = O(r2), v2 = (m3.utcOffset() - this.utcOffset()) * e, g2 = this - m3, D2 = function() {
263
- return b.m(y2, m3);
264
- };
265
- switch (M3) {
266
- case h:
267
- $3 = D2() / 12;
268
- break;
269
- case c:
270
- $3 = D2();
271
- break;
272
- case f:
273
- $3 = D2() / 3;
274
- break;
275
- case o:
276
- $3 = (g2 - v2) / 604800000;
277
- break;
278
- case a:
279
- $3 = (g2 - v2) / 86400000;
280
- break;
281
- case u:
282
- $3 = g2 / n;
283
- break;
284
- case s:
285
- $3 = g2 / e;
286
- break;
287
- case i:
288
- $3 = g2 / t;
289
- break;
290
- default:
291
- $3 = g2;
292
- }
293
- return l2 ? $3 : b.a($3);
294
- }, m2.daysInMonth = function() {
295
- return this.endOf(c).$D;
296
- }, m2.$locale = function() {
297
- return D[this.$L];
298
- }, m2.locale = function(t2, e2) {
299
- if (!t2)
300
- return this.$L;
301
- var n2 = this.clone(), r2 = w(t2, e2, true);
302
- return r2 && (n2.$L = r2), n2;
303
- }, m2.clone = function() {
304
- return b.w(this.$d, this);
305
- }, m2.toDate = function() {
306
- return new Date(this.valueOf());
307
- }, m2.toJSON = function() {
308
- return this.isValid() ? this.toISOString() : null;
309
- }, m2.toISOString = function() {
310
- return this.$d.toISOString();
311
- }, m2.toString = function() {
312
- return this.$d.toUTCString();
313
- }, M2;
314
- }(), Y = _.prototype;
315
- return O.prototype = Y, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", c], ["$y", h], ["$D", d]].forEach(function(t2) {
316
- Y[t2[1]] = function(e2) {
317
- return this.$g(e2, t2[0], t2[1]);
318
- };
319
- }), O.extend = function(t2, e2) {
320
- return t2.$i || (t2(e2, _, O), t2.$i = true), O;
321
- }, O.locale = w, O.isDayjs = S, O.unix = function(t2) {
322
- return O(1000 * t2);
323
- }, O.en = D[g], O.Ls = D, O.p = {}, O;
324
- });
325
- });
326
-
327
5
  // pkgs/@akanjs/devkit/aiEditor.ts
328
6
  import { input, select } from "@inquirer/prompts";
329
7
  import {
@@ -337,10 +15,7 @@ import { ChatOpenAI } from "@langchain/openai";
337
15
  import { Logger as Logger2 } from "akanjs/common";
338
16
  import chalk from "chalk";
339
17
 
340
- // pkgs/@akanjs/devkit/auth.ts
341
- import { mkdir } from "fs/promises";
342
-
343
- // pkgs/@akanjs/devkit/constants.ts
18
+ // pkgs/@akanjs/devkit/cloud/constants.ts
344
19
  var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
345
20
  var configPath = `${basePath}/config.json`;
346
21
  var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
@@ -348,9 +23,14 @@ var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE ===
348
23
  var defaultHostConfig = {};
349
24
  var defaultAkanGlobalConfig = {
350
25
  cloudHost: {},
26
+ remoteEnvServers: {},
351
27
  llm: null
352
28
  };
353
29
 
30
+ // pkgs/@akanjs/devkit/cloud/globalConfig.ts
31
+ import { mkdir } from "fs/promises";
32
+ import dayjs from "dayjs";
33
+
354
34
  // pkgs/@akanjs/devkit/fileSys.ts
355
35
  import { stat } from "fs/promises";
356
36
  import { Logger } from "akanjs/common";
@@ -389,35 +69,198 @@ class FileSys {
389
69
  }
390
70
  }
391
71
 
392
- // pkgs/@akanjs/devkit/auth.ts
393
- var getAkanGlobalConfig = async () => {
394
- const exists = await FileSys.fileExists(configPath);
395
- const akanConfig = exists ? await FileSys.readJson(configPath) : defaultAkanGlobalConfig;
396
- return akanConfig;
397
- };
398
- var setAkanGlobalConfig = async (akanConfig) => {
399
- await mkdir(basePath, { recursive: true });
400
- await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
401
- };
402
- var getHostConfig = async (host = akanCloudHost) => {
403
- const akanConfig = await getAkanGlobalConfig();
404
- return akanConfig.cloudHost[host] ?? defaultHostConfig;
405
- };
406
- var setHostConfig = async (host = akanCloudHost, config = {}) => {
407
- const akanConfig = await getAkanGlobalConfig();
408
- akanConfig.cloudHost[host] = config;
409
- await setAkanGlobalConfig(akanConfig);
410
- };
411
- var getSelf = async (token) => {
412
- try {
413
- const res = await fetch(`${akanCloudUrl}/user/getSelf`, { headers: { Authorization: `Bearer ${token}` } });
414
- const user = await res.json();
415
- return user;
416
- } catch (e) {
417
- return null;
72
+ // pkgs/@akanjs/devkit/cloud/globalConfig.ts
73
+ class GlobalConfig {
74
+ static async#getAkanGlobalConfig() {
75
+ const exists = await FileSys.fileExists(configPath);
76
+ const akanConfig = exists ? await FileSys.readJson(configPath) : {};
77
+ return {
78
+ ...defaultAkanGlobalConfig,
79
+ ...akanConfig,
80
+ cloudHost: akanConfig.cloudHost ?? defaultAkanGlobalConfig.cloudHost,
81
+ remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers
82
+ };
418
83
  }
419
- };
84
+ static async#setAkanGlobalConfig(akanConfig) {
85
+ await mkdir(basePath, { recursive: true });
86
+ await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
87
+ }
88
+ static async getHostConfig(host = akanCloudHost) {
89
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
90
+ return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? defaultHostConfig);
91
+ }
92
+ static async setHostConfig(host = akanCloudHost, config = {}) {
93
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
94
+ akanConfig.cloudHost[host] = GlobalConfig.toHostConfigDto(config);
95
+ await GlobalConfig.#setAkanGlobalConfig(akanConfig);
96
+ }
97
+ static async getLlmConfig() {
98
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
99
+ return akanConfig.llm ?? null;
100
+ }
101
+ static async setLlmConfig(llmConfig) {
102
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
103
+ await GlobalConfig.#setAkanGlobalConfig({ ...akanConfig, llm: llmConfig });
104
+ }
105
+ static async getRemoteEnvServers() {
106
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
107
+ return akanConfig.remoteEnvServers;
108
+ }
109
+ static async setRemoteEnvServer(name, config) {
110
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
111
+ await GlobalConfig.#setAkanGlobalConfig({
112
+ ...akanConfig,
113
+ remoteEnvServers: {
114
+ ...akanConfig.remoteEnvServers,
115
+ [name]: config
116
+ }
117
+ });
118
+ }
119
+ static async removeRemoteEnvServer(name) {
120
+ const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
121
+ const { [name]: _, ...remoteEnvServers } = akanConfig.remoteEnvServers;
122
+ await GlobalConfig.#setAkanGlobalConfig({
123
+ ...akanConfig,
124
+ remoteEnvServers
125
+ });
126
+ }
127
+ static needRefreshToken(accessToken) {
128
+ return !!accessToken?.expiresAt?.isBefore(dayjs().add(1, "hour"));
129
+ }
130
+ static toAccessToken(accessToken) {
131
+ return {
132
+ jwt: accessToken.jwt,
133
+ refreshToken: accessToken.refreshToken ?? null,
134
+ expiresAt: accessToken.expiresAt ? dayjs(accessToken.expiresAt) : null
135
+ };
136
+ }
137
+ static toAccessTokenDto(accessToken) {
138
+ return {
139
+ jwt: accessToken.jwt,
140
+ refreshToken: accessToken.refreshToken ?? null,
141
+ expiresAt: accessToken.expiresAt?.toString() ?? null
142
+ };
143
+ }
144
+ static toHostConfigDto(hostConfig) {
145
+ return {
146
+ auth: {
147
+ accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
148
+ self: hostConfig.auth?.self
149
+ }
150
+ };
151
+ }
152
+ static toHostConfig(hostConfigDto) {
153
+ return {
154
+ auth: {
155
+ accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
156
+ self: hostConfigDto.auth?.self
157
+ }
158
+ };
159
+ }
160
+ }
161
+
162
+ // pkgs/@akanjs/devkit/cloud/cloudApi.ts
163
+ class HttpClient {
164
+ baseUrl;
165
+ headers = {};
166
+ constructor(baseUrl, headers = {}) {
167
+ this.baseUrl = baseUrl;
168
+ this.headers = headers;
169
+ }
170
+ async get(url, { headers } = {}) {
171
+ const response = await fetch(`${this.baseUrl}${url}`, {
172
+ headers: {
173
+ "Content-Type": "application/json",
174
+ ...this.headers,
175
+ ...headers
176
+ }
177
+ });
178
+ return response.json();
179
+ }
180
+ async getFile(url, localPath, headers) {
181
+ const response = await fetch(`${this.baseUrl}${url}`, {
182
+ headers: { ...this.headers, ...headers }
183
+ });
184
+ if (!response.ok)
185
+ throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
186
+ await Bun.write(localPath, response);
187
+ }
188
+ async post(url, data, { headers } = {}) {
189
+ const isFormData = data instanceof FormData;
190
+ const response = await fetch(`${this.baseUrl}${url}`, {
191
+ method: "POST",
192
+ body: isFormData ? data : JSON.stringify(data),
193
+ headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
194
+ });
195
+ return response.json();
196
+ }
197
+ setHeaders(headers) {
198
+ Object.assign(this.headers, headers);
199
+ return this;
200
+ }
201
+ }
420
202
 
203
+ class CloudApi {
204
+ #api;
205
+ #accessToken = null;
206
+ static async fromHost(host) {
207
+ const hostConfig = await GlobalConfig.getHostConfig(host);
208
+ return new CloudApi(hostConfig);
209
+ }
210
+ constructor(hostConfig) {
211
+ const host = akanCloudHost;
212
+ this.#api = new HttpClient(`${host}/api`);
213
+ this.#accessToken = hostConfig.auth?.accessToken ?? null;
214
+ if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
215
+ this.#api.setHeaders({
216
+ Authorization: `Bearer ${this.#accessToken.jwt}`
217
+ });
218
+ }
219
+ async uploadEnv(devProjectId, file) {
220
+ const formData = new FormData;
221
+ formData.append("devProjectId", devProjectId);
222
+ formData.append("file", file);
223
+ const data = await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
224
+ return data;
225
+ }
226
+ async downloadEnv(devProjectId, localPath) {
227
+ await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
228
+ }
229
+ async getRemoteAuthToken(remoteId) {
230
+ try {
231
+ if (this.#accessToken) {
232
+ if (GlobalConfig.needRefreshToken(this.#accessToken))
233
+ return await this.refreshAuthToken();
234
+ else
235
+ return await this.refreshAuthToken();
236
+ }
237
+ const accessToken = await this.#api.get(`/getRemoteAuthToken/${remoteId}`);
238
+ this.#accessToken = GlobalConfig.toAccessToken(accessToken);
239
+ this.#api.setHeaders({
240
+ Authorization: `Bearer ${this.#accessToken.jwt}`
241
+ });
242
+ return this.#accessToken;
243
+ } catch (_) {
244
+ return null;
245
+ }
246
+ }
247
+ async refreshAuthToken() {
248
+ const response = await this.#api.post(`/refreshRemoteAuthToken`, {
249
+ refreshToken: this.#accessToken?.refreshToken
250
+ });
251
+ this.#accessToken = GlobalConfig.toAccessToken(response);
252
+ this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
253
+ return this.#accessToken;
254
+ }
255
+ async getRemoteSelf() {
256
+ try {
257
+ const data = await this.#api.get(`/getRemoteSelf`);
258
+ return data;
259
+ } catch {
260
+ return null;
261
+ }
262
+ }
263
+ }
421
264
  // pkgs/@akanjs/devkit/spinner.ts
422
265
  import ora from "ora";
423
266
 
@@ -480,12 +323,43 @@ class Spinner {
480
323
 
481
324
  // pkgs/@akanjs/devkit/aiEditor.ts
482
325
  var MAX_ASK_TRY = 300;
483
- var supportedLlmModels = ["deepseek-chat", "deepseek-reasoner"];
326
+ var supportedLlmModels = [
327
+ "deepseek-chat",
328
+ "deepseek-reasoner"
329
+ ];
330
+ var parseTypescriptFileBlocks = (text) => {
331
+ const fileBlocks = [];
332
+ const codeBlockRegex = /```(?:typescript|ts|tsx)\s*\n([\s\S]*?)```/gi;
333
+ const filePathRegex = /^\s*\/\/\s*File:\s*(.+?)\s*$/im;
334
+ for (const codeBlock of text.matchAll(codeBlockRegex)) {
335
+ const content = codeBlock[1]?.trim();
336
+ if (!content)
337
+ continue;
338
+ const filePath = filePathRegex.exec(content)?.[1]?.trim();
339
+ if (!filePath)
340
+ continue;
341
+ fileBlocks.push({
342
+ filePath,
343
+ content: content.replace(filePathRegex, "").trim()
344
+ });
345
+ }
346
+ return fileBlocks;
347
+ };
348
+ var preserveTypescriptResponseContent = (previousContent, nextContent) => {
349
+ const previousWrites = parseTypescriptFileBlocks(previousContent);
350
+ const nextWrites = parseTypescriptFileBlocks(nextContent);
351
+ if (previousWrites.length > 0 && nextWrites.length === 0)
352
+ return previousContent;
353
+ return nextContent;
354
+ };
484
355
 
485
356
  class AiSession {
486
357
  static #cacheDir = "node_modules/.cache/akan/aiSession";
487
358
  static #chat = null;
488
- static async init({ temperature = 0, useExisting = true } = {}) {
359
+ static async init({
360
+ temperature = 0,
361
+ useExisting = true
362
+ } = {}) {
489
363
  if (useExisting) {
490
364
  const llmConfig2 = await AiSession.getLlmConfig();
491
365
  if (llmConfig2) {
@@ -512,22 +386,24 @@ class AiSession {
512
386
  return AiSession;
513
387
  }
514
388
  static async getLlmConfig() {
515
- const akanConfig = await getAkanGlobalConfig();
516
- return akanConfig.llm ?? null;
389
+ return await GlobalConfig.getLlmConfig();
517
390
  }
518
391
  static async setLlmConfig(llmConfig) {
519
- const akanConfig = await getAkanGlobalConfig();
520
- akanConfig.llm = llmConfig;
521
- await setAkanGlobalConfig(akanConfig);
392
+ await GlobalConfig.setLlmConfig(llmConfig);
522
393
  return AiSession;
523
394
  }
524
395
  static async#requestLlmConfig() {
525
- const model = await select({ message: "Select a LLM model", choices: supportedLlmModels });
396
+ const model = await select({
397
+ message: "Select a LLM model",
398
+ choices: supportedLlmModels
399
+ });
526
400
  const apiKey = await input({ message: "Enter your API key" });
527
401
  return { model, apiKey };
528
402
  }
529
403
  static async#validateApiKey(modelName, apiKey) {
530
- const spinner = new Spinner("Validating LLM API key...", { prefix: `\uD83E\uDD16akan-editor` }).start();
404
+ const spinner = new Spinner("Validating LLM API key...", {
405
+ prefix: `\uD83E\uDD16akan-editor`
406
+ }).start();
531
407
  const chat = new ChatOpenAI({
532
408
  modelName,
533
409
  temperature: 0,
@@ -550,7 +426,11 @@ class AiSession {
550
426
  sessionKey;
551
427
  isCacheLoaded = false;
552
428
  workspace;
553
- constructor(type, { workspace, cacheKey, isContinued }) {
429
+ constructor(type, {
430
+ workspace,
431
+ cacheKey,
432
+ isContinued
433
+ }) {
554
434
  this.workspace = workspace;
555
435
  this.sessionKey = `${type}${cacheKey ? `-${cacheKey}` : ""}`;
556
436
  if (isContinued)
@@ -591,7 +471,7 @@ class AiSession {
591
471
  const humanMessage = new HumanMessage(question);
592
472
  this.messageHistory.push(humanMessage);
593
473
  const stream = await AiSession.#chat.stream(this.messageHistory);
594
- let reasoningResponse = "", fullResponse = "", tokenIdx = 0;
474
+ let reasoningResponse = "", fullResponse = "";
595
475
  for await (const chunk of stream) {
596
476
  if (loader.isSpinning())
597
477
  loader.succeed(`${AiSession.#chat.model} responded`);
@@ -612,7 +492,6 @@ class AiSession {
612
492
  fullResponse += content;
613
493
  onChunk(content);
614
494
  }
615
- tokenIdx++;
616
495
  }
617
496
  fullResponse += `
618
497
  `;
@@ -620,19 +499,33 @@ class AiSession {
620
499
  `);
621
500
  this.messageHistory.push(new AIMessage(fullResponse));
622
501
  return { content: fullResponse, messageHistory: this.messageHistory };
623
- } catch (error) {
502
+ } catch {
624
503
  loader.fail(`${AiSession.#chat.model} failed to respond`);
625
504
  throw new Error("Failed to stream response");
626
505
  }
627
506
  }
628
- async edit(question, { onChunk, onReasoning, maxTry = MAX_ASK_TRY, validate, approve } = {}) {
507
+ async edit(question, {
508
+ onChunk,
509
+ onReasoning,
510
+ maxTry = MAX_ASK_TRY,
511
+ validate,
512
+ approve,
513
+ fallbackToPreviousTypescript
514
+ } = {}) {
629
515
  for (let tryCount = 0;tryCount < maxTry; tryCount++) {
630
516
  let response = await this.ask(question, { onChunk, onReasoning });
631
517
  if (validate?.length && tryCount === 0) {
632
518
  const validateQuestion = `Double check if the response meets the requirements and conditions, and follow the instructions. If not, rewrite it.
633
519
  ${validate.map((v) => `- ${v}`).join(`
634
520
  `)}`;
635
- response = await this.ask(validateQuestion, { onChunk, onReasoning });
521
+ const validateResponse = await this.ask(validateQuestion, {
522
+ onChunk,
523
+ onReasoning
524
+ });
525
+ response = {
526
+ ...validateResponse,
527
+ content: fallbackToPreviousTypescript ? preserveTypescriptResponseContent(response.content, validateResponse.content) : validateResponse.content
528
+ };
636
529
  }
637
530
  const isConfirmed = approve ? true : await select({
638
531
  message: "Do you want to edit the response?",
@@ -665,28 +558,45 @@ ${validate.map((v) => `- ${v}`).join(`
665
558
  return this;
666
559
  }
667
560
  async writeTypescripts(question, executor, options = {}) {
668
- const content = await this.edit(question, options);
561
+ const content = await this.edit(question, {
562
+ ...options,
563
+ fallbackToPreviousTypescript: true
564
+ });
669
565
  const writes = this.#getTypescriptCodes(content);
566
+ if (!writes.length)
567
+ throw new Error("No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.");
670
568
  for (const write of writes)
671
569
  await executor.writeFile(write.filePath, write.content);
672
570
  return await this.#tryFixTypescripts(writes, executor, options);
673
571
  }
674
- async#editTypescripts(question, options = {}) {
675
- const content = await this.edit(question, options);
676
- return this.#getTypescriptCodes(content);
572
+ async#editTypescripts(question, options = {}, fallbackWrites) {
573
+ const content = await this.edit(question, {
574
+ ...options,
575
+ fallbackToPreviousTypescript: true
576
+ });
577
+ const writes = this.#getTypescriptCodes(content);
578
+ if (!writes.length && fallbackWrites?.length)
579
+ return fallbackWrites;
580
+ if (!writes.length)
581
+ throw new Error("No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.");
582
+ return writes;
677
583
  }
678
584
  async#tryFixTypescripts(writes, executor, options = {}) {
679
585
  const MAX_EDIT_TRY = 5;
680
586
  for (let tryCount = 0;tryCount < MAX_EDIT_TRY; tryCount++) {
681
- const loader = new Spinner(`Type checking and linting...`, { prefix: `\uD83E\uDD16akan-editor` }).start();
587
+ const loader = new Spinner(`Type checking and linting...`, {
588
+ prefix: `\uD83E\uDD16akan-editor`
589
+ }).start();
682
590
  const fileChecks = await Promise.all(writes.map(async ({ filePath }) => {
683
- const typeCheckResult = executor.typeCheck(filePath);
684
- const lintResult = await executor.lint(filePath);
685
- const needFix2 = !!typeCheckResult.fileErrors.length || !!lintResult.errors.length;
686
- return { filePath, typeCheckResult, lintResult, needFix: needFix2 };
591
+ const lintResult = await executor.lint(filePath, { fix: true });
592
+ const typeCheckResult = await executor.typeCheckAsync(filePath);
593
+ const hasTypeErrors = typeCheckResult.fileErrors.length > 0;
594
+ const hasLintErrors = lintResult.errors.length > 0;
595
+ const needFix = hasTypeErrors || hasLintErrors;
596
+ return { filePath, typeCheckResult, lintResult, needFix };
687
597
  }));
688
- const needFix = fileChecks.some((fileCheck) => fileCheck.needFix);
689
- if (needFix) {
598
+ const hasAnyFix = fileChecks.some((fileCheck) => fileCheck.needFix);
599
+ if (hasAnyFix) {
690
600
  loader.fail("Type checking and linting has some errors, try to fix them");
691
601
  fileChecks.forEach((fileCheck) => {
692
602
  Logger2.rawLog(`TypeCheck Result
@@ -702,7 +612,7 @@ ${fileCheck.lintResult.message}`);
702
612
  ...options,
703
613
  validate: undefined,
704
614
  approve: true
705
- });
615
+ }, writes);
706
616
  for (const write of writes)
707
617
  await executor.writeFile(write.filePath, write.content);
708
618
  } else {
@@ -713,21 +623,7 @@ ${fileCheck.lintResult.message}`);
713
623
  throw new Error("Failed to create scalar");
714
624
  }
715
625
  #getTypescriptCodes(text) {
716
- const codes = text.match(/```(typescript|tsx)([\s\S]*?)```/g);
717
- if (!codes)
718
- return [];
719
- const result = codes.map((code) => {
720
- const content = /```(typescript|tsx)([\s\S]*?)```/.exec(code)?.[2];
721
- if (!content)
722
- return null;
723
- const filePath = /\/\/ File: (.*?)(?:\n|$)/.exec(content)?.[1]?.trim();
724
- if (!filePath)
725
- return null;
726
- const contentWithoutFilepath = content.replace(`// File: ${filePath}
727
- `, "").trim();
728
- return { filePath, content: contentWithoutFilepath };
729
- });
730
- return result.filter((code) => code !== null);
626
+ return parseTypescriptFileBlocks(text);
731
627
  }
732
628
  async editMarkdown(request, options = {}) {
733
629
  const content = await this.edit(request, options);
@@ -745,21 +641,26 @@ ${fileCheck.lintResult.message}`);
745
641
  }
746
642
  // pkgs/@akanjs/devkit/akanApp/akanApp.host.ts
747
643
  import path9 from "path";
748
- import { Logger as Logger6 } from "akanjs/common";
644
+ import { Logger as Logger5 } from "akanjs/common";
749
645
 
750
646
  // pkgs/@akanjs/devkit/executors.ts
751
647
  import {
752
648
  exec,
753
649
  fork,
754
- spawn
650
+ spawn as spawn2
755
651
  } from "child_process";
756
652
  import { readFileSync as readFileSync3 } from "fs";
757
- import { copyFile, mkdir as mkdir2, readdir as readDirEntries, stat as stat2 } from "fs/promises";
653
+ import {
654
+ copyFile,
655
+ mkdir as mkdir2,
656
+ readdir as readDirEntries,
657
+ stat as stat2
658
+ } from "fs/promises";
758
659
  import path7 from "path";
759
660
  import {
760
661
  capitalize,
761
662
  isRouteSourceFile,
762
- Logger as Logger4,
663
+ Logger as Logger3,
763
664
  parseRouteModuleKey,
764
665
  validatePageSourceFile,
765
666
  validateSubRoutePageKey
@@ -1122,23 +1023,146 @@ import path2 from "path";
1122
1023
  var getDirname = (url) => path2.dirname(new URL(url).pathname);
1123
1024
 
1124
1025
  // pkgs/@akanjs/devkit/linter.ts
1026
+ import { spawn } from "child_process";
1125
1027
  import { existsSync, readFileSync } from "fs";
1126
- import * as path3 from "path";
1127
- import { Logger as Logger3 } from "akanjs/common";
1028
+ import path3 from "path";
1128
1029
  import chalk2 from "chalk";
1129
1030
 
1130
1031
  class Linter {
1131
- #logger = new Logger3("Linter");
1132
1032
  lintRoot;
1033
+ #biomeBin;
1133
1034
  constructor(cwdPath) {
1134
- this.lintRoot = this.#findEslintRootPath(cwdPath);
1035
+ this.lintRoot = this.#findBiomeRootPath(cwdPath);
1036
+ const localBiomeBin = path3.join(this.lintRoot, "node_modules/.bin/biome");
1037
+ this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
1135
1038
  }
1136
- #findEslintRootPath(dir) {
1137
- const configPath2 = path3.join(dir, "eslint.config.ts");
1039
+ #findBiomeRootPath(dir) {
1040
+ const configPath2 = path3.join(dir, "biome.json");
1138
1041
  if (existsSync(configPath2))
1139
1042
  return dir;
1140
1043
  const parentDir = path3.dirname(dir);
1141
- return this.#findEslintRootPath(parentDir);
1044
+ if (parentDir === dir)
1045
+ throw new Error(`biome.json not found from ${dir}`);
1046
+ return this.#findBiomeRootPath(parentDir);
1047
+ }
1048
+ #toBiomePath(filePath) {
1049
+ const relativePath = path3.relative(this.lintRoot, filePath);
1050
+ if (!relativePath.startsWith("..") && !path3.isAbsolute(relativePath))
1051
+ return relativePath;
1052
+ return filePath;
1053
+ }
1054
+ #resolveFilePath(filePath) {
1055
+ return path3.isAbsolute(filePath) ? filePath : path3.join(this.lintRoot, filePath);
1056
+ }
1057
+ async#runBiome(args, input2) {
1058
+ return await new Promise((resolve, reject) => {
1059
+ const proc = spawn(this.#biomeBin, args, {
1060
+ cwd: this.lintRoot,
1061
+ stdio: ["pipe", "pipe", "pipe"]
1062
+ });
1063
+ let stdout = "";
1064
+ let stderr = "";
1065
+ proc.stdout.on("data", (data) => {
1066
+ stdout += data.toString();
1067
+ });
1068
+ proc.stderr.on("data", (data) => {
1069
+ stderr += data.toString();
1070
+ });
1071
+ proc.on("error", reject);
1072
+ proc.on("close", (code) => resolve({ stdout, stderr, code }));
1073
+ proc.stdin.end(input2);
1074
+ });
1075
+ }
1076
+ #parseBiomeReport(output) {
1077
+ const jsonStart = output.indexOf("{");
1078
+ const jsonEnd = output.lastIndexOf("}");
1079
+ if (jsonStart === -1 || jsonEnd === -1 || jsonEnd < jsonStart)
1080
+ throw new Error(output.trim() || "No Biome JSON output");
1081
+ return JSON.parse(output.slice(jsonStart, jsonEnd + 1));
1082
+ }
1083
+ #diagnosticFilePath(diagnostic, fallbackFilePath) {
1084
+ const diagnosticPath = diagnostic.location?.path;
1085
+ if (!diagnosticPath)
1086
+ return fallbackFilePath;
1087
+ return path3.isAbsolute(diagnosticPath) ? diagnosticPath : path3.join(this.lintRoot, diagnosticPath);
1088
+ }
1089
+ #createLintMessage(diagnostic) {
1090
+ const start = diagnostic.location?.start;
1091
+ const end = diagnostic.location?.end;
1092
+ return {
1093
+ line: Math.max(1, start?.line ?? 1),
1094
+ column: Math.max(1, start?.column ?? 1),
1095
+ endLine: end?.line,
1096
+ endColumn: end?.column,
1097
+ message: diagnostic.message,
1098
+ ruleId: diagnostic.category ?? null,
1099
+ severity: diagnostic.severity === "error" ? 2 : 1
1100
+ };
1101
+ }
1102
+ #toLintResults(report, filePath) {
1103
+ const resultsByPath = new Map;
1104
+ for (const diagnostic of report.diagnostics ?? []) {
1105
+ if (diagnostic.severity !== "error" && diagnostic.severity !== "warning")
1106
+ continue;
1107
+ const diagnosticFilePath = this.#diagnosticFilePath(diagnostic, filePath);
1108
+ const result = resultsByPath.get(diagnosticFilePath) ?? {
1109
+ filePath: diagnosticFilePath,
1110
+ messages: [],
1111
+ errorCount: 0,
1112
+ warningCount: 0,
1113
+ fixableErrorCount: 0,
1114
+ fixableWarningCount: 0
1115
+ };
1116
+ const message = this.#createLintMessage(diagnostic);
1117
+ result.messages.push(message);
1118
+ if (message.severity === 2)
1119
+ result.errorCount += 1;
1120
+ else
1121
+ result.warningCount += 1;
1122
+ resultsByPath.set(diagnosticFilePath, result);
1123
+ }
1124
+ return [
1125
+ resultsByPath.get(filePath) ?? {
1126
+ filePath,
1127
+ messages: [],
1128
+ errorCount: 0,
1129
+ warningCount: 0,
1130
+ fixableErrorCount: 0,
1131
+ fixableWarningCount: 0
1132
+ },
1133
+ ...[...resultsByPath.entries()].filter(([resultPath]) => resultPath !== filePath).map(([, result]) => result)
1134
+ ];
1135
+ }
1136
+ #splitMessages(results) {
1137
+ const messages = results.flatMap((result) => result.messages);
1138
+ return {
1139
+ errors: messages.filter((message) => message.severity === 2),
1140
+ warnings: messages.filter((message) => message.severity === 1)
1141
+ };
1142
+ }
1143
+ async#checkFile(filePath, { write = false } = {}) {
1144
+ const originalContent = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
1145
+ const { stdout, stderr } = await this.#runBiome([
1146
+ "check",
1147
+ ...write ? ["--write"] : [],
1148
+ "--reporter=json",
1149
+ "--max-diagnostics=none",
1150
+ "--no-errors-on-unmatched",
1151
+ "--config-path",
1152
+ path3.join(this.lintRoot, "biome.json"),
1153
+ this.#toBiomePath(filePath)
1154
+ ]);
1155
+ const report = this.#parseBiomeReport(stdout || stderr);
1156
+ const results = this.#toLintResults(report, filePath);
1157
+ const { errors, warnings } = this.#splitMessages(results);
1158
+ const output = write && existsSync(filePath) ? readFileSync(filePath, "utf8") : undefined;
1159
+ return {
1160
+ fixed: write && output !== originalContent,
1161
+ output,
1162
+ results,
1163
+ errors,
1164
+ warnings
1165
+ };
1142
1166
  }
1143
1167
  async lint(filePath, { fix = false, dryRun = false } = {}) {
1144
1168
  if (fix)
@@ -1146,9 +1170,10 @@ class Linter {
1146
1170
  return await this.lintFile(filePath);
1147
1171
  }
1148
1172
  async lintFile(filePath) {
1149
- if (!existsSync(filePath))
1173
+ const resolvedFilePath = this.#resolveFilePath(filePath);
1174
+ if (!existsSync(resolvedFilePath))
1150
1175
  throw new Error(`File not found: ${filePath}`);
1151
- return { fixed: false, results: [], errors: [], warnings: [] };
1176
+ return await this.#checkFile(resolvedFilePath);
1152
1177
  }
1153
1178
  formatLintResults(results) {
1154
1179
  if (results.length === 0)
@@ -1168,12 +1193,12 @@ ${chalk2.cyan(result.filePath)}`);
1168
1193
  const sourceContent = readFileSync(result.filePath, "utf8");
1169
1194
  sourceLines = sourceContent.split(`
1170
1195
  `);
1171
- } catch (error) {}
1196
+ } catch {}
1172
1197
  }
1173
1198
  result.messages.forEach((message) => {
1174
1199
  const type = message.severity === 2 ? "error" : "warning";
1175
1200
  const typeColor = message.severity === 2 ? chalk2.red : chalk2.yellow;
1176
- const icon = message.severity === 2 ? "\u274C" : "\u26A0\uFE0F";
1201
+ const icon = message.severity === 2 ? "x" : "!";
1177
1202
  const ruleInfo = message.ruleId ? chalk2.dim(` (${message.ruleId})`) : "";
1178
1203
  output.push(`
1179
1204
  ${icon} ${typeColor(type)}: ${message.message}${ruleInfo}`);
@@ -1192,7 +1217,7 @@ ${chalk2.dim(`${lineNumber} |`)} ${sourceLine}`);
1192
1217
  }
1193
1218
  });
1194
1219
  if (totalErrors === 0 && totalWarnings === 0)
1195
- return chalk2.bold("\u2705 No ESLint errors or warnings found");
1220
+ return chalk2.bold("No Biome errors or warnings found");
1196
1221
  const errorText = totalErrors > 0 ? chalk2.red(`${totalErrors} error(s)`) : "0 errors";
1197
1222
  const warningText = totalWarnings > 0 ? chalk2.yellow(`${totalWarnings} warning(s)`) : "0 warnings";
1198
1223
  const summary = [`
@@ -1207,23 +1232,26 @@ ${errorText}, ${warningText} found`];
1207
1232
  column: message.column,
1208
1233
  message: message.message,
1209
1234
  ruleId: message.ruleId,
1210
- severity: message.severity === 2 ? "error" : "warning",
1211
- fix: message.fix,
1212
- suggestions: message.suggestions
1235
+ severity: message.severity === 2 ? "error" : "warning"
1213
1236
  })));
1214
1237
  const stats = results.reduce((acc, result) => ({
1215
1238
  errorCount: acc.errorCount + result.errorCount,
1216
1239
  warningCount: acc.warningCount + result.warningCount,
1217
1240
  fixableErrorCount: acc.fixableErrorCount + result.fixableErrorCount,
1218
1241
  fixableWarningCount: acc.fixableWarningCount + result.fixableWarningCount
1219
- }), { errorCount: 0, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0 });
1242
+ }), {
1243
+ errorCount: 0,
1244
+ warningCount: 0,
1245
+ fixableErrorCount: 0,
1246
+ fixableWarningCount: 0
1247
+ });
1220
1248
  return { results, details, stats };
1221
1249
  }
1222
1250
  async hasNoLintErrors(filePath) {
1223
1251
  try {
1224
1252
  const { results } = await this.lintFile(filePath);
1225
1253
  return results.every((result) => result.errorCount === 0);
1226
- } catch (error) {
1254
+ } catch {
1227
1255
  return false;
1228
1256
  }
1229
1257
  }
@@ -1236,12 +1264,28 @@ ${errorText}, ${warningText} found`];
1236
1264
  return results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
1237
1265
  }
1238
1266
  async fixFile(filePath, dryRun = false) {
1239
- if (!existsSync(filePath))
1267
+ const resolvedFilePath = this.#resolveFilePath(filePath);
1268
+ if (!existsSync(resolvedFilePath))
1240
1269
  throw new Error(`File not found: ${filePath}`);
1241
- return { fixed: false, output: undefined, results: [], errors: [], warnings: [] };
1270
+ if (!dryRun)
1271
+ return await this.#checkFile(resolvedFilePath, { write: true });
1272
+ const source = readFileSync(resolvedFilePath, "utf8");
1273
+ const { stdout } = await this.#runBiome([
1274
+ "check",
1275
+ "--write",
1276
+ "--config-path",
1277
+ path3.join(this.lintRoot, "biome.json"),
1278
+ "--stdin-file-path",
1279
+ this.#toBiomePath(resolvedFilePath)
1280
+ ], source);
1281
+ const lintResult = await this.lintFile(resolvedFilePath);
1282
+ return { ...lintResult, fixed: stdout !== source, output: stdout };
1242
1283
  }
1243
1284
  async getConfigForFile(filePath) {
1244
- return {};
1285
+ const resolvedFilePath = this.#resolveFilePath(filePath);
1286
+ if (!existsSync(resolvedFilePath))
1287
+ throw new Error(`File not found: ${filePath}`);
1288
+ return JSON.parse(readFileSync(path3.join(this.lintRoot, "biome.json"), "utf8"));
1245
1289
  }
1246
1290
  async getProblematicRules(filePath) {
1247
1291
  const { results } = await this.lintFile(filePath);
@@ -1631,23 +1675,23 @@ async function assertScanConvention(exec, libRoot) {
1631
1675
  files.filter((filename) => !appRootAllowedFiles.has(filename)).forEach((filename) => {
1632
1676
  addViolation(filename, "unsupported app root file");
1633
1677
  });
1634
- dirs.filter((dirname2) => !appRootAllowedDirs.has(dirname2)).forEach((dirname2) => {
1635
- addViolation(dirname2, "unsupported app root folder");
1678
+ dirs.filter((dirname) => !appRootAllowedDirs.has(dirname)).forEach((dirname) => {
1679
+ addViolation(dirname, "unsupported app root folder");
1636
1680
  });
1637
1681
  }
1638
1682
  libRoot.files.filter((filename) => !isAllowedLibRootFile(filename)).forEach((filename) => {
1639
1683
  addViolation(path5.join("lib", filename), "unsupported lib root file");
1640
1684
  });
1641
- libRoot.dirs.filter((dirname2) => dirname2.startsWith("__") && !internalLibDirs.has(dirname2)).forEach((dirname2) => {
1642
- addViolation(path5.join("lib", dirname2), "unsupported internal lib folder");
1685
+ libRoot.dirs.filter((dirname) => dirname.startsWith("__") && !internalLibDirs.has(dirname)).forEach((dirname) => {
1686
+ addViolation(path5.join("lib", dirname), "unsupported internal lib folder");
1643
1687
  });
1644
- const databaseDirs = libRoot.dirs.filter((dirname2) => !dirname2.startsWith("_"));
1645
- const serviceDirs = libRoot.dirs.filter((dirname2) => dirname2.startsWith("_") && !dirname2.startsWith("__"));
1688
+ const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
1689
+ const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
1646
1690
  const scalarDirs = await exec.readdir("lib/__scalar");
1647
1691
  await Promise.all([
1648
- ...databaseDirs.map((dirname2) => validateModuleFiles(exec, violations, "database", path5.join("lib", dirname2))),
1649
- ...serviceDirs.map((dirname2) => validateModuleFiles(exec, violations, "service", path5.join("lib", dirname2))),
1650
- ...scalarDirs.map((dirname2) => validateModuleFiles(exec, violations, "scalar", path5.join("lib/__scalar", dirname2)))
1692
+ ...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path5.join("lib", dirname))),
1693
+ ...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path5.join("lib", dirname))),
1694
+ ...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path5.join("lib/__scalar", dirname)))
1651
1695
  ]);
1652
1696
  if (violations.length > 0) {
1653
1697
  throw new Error(`[scan-convention]
@@ -1657,8 +1701,8 @@ ${violations.sort().map((violation) => `- ${violation}`).join(`
1657
1701
  }
1658
1702
  async function validateModuleFiles(exec, violations, kind, modulePath) {
1659
1703
  const { files, dirs } = await exec.getFilesAndDirs(modulePath);
1660
- dirs.forEach((dirname2) => {
1661
- violations.push(`${getScanPath(exec, path5.join(modulePath, dirname2))}: unsupported module folder`);
1704
+ dirs.forEach((dirname) => {
1705
+ violations.push(`${getScanPath(exec, path5.join(modulePath, dirname))}: unsupported module folder`);
1662
1706
  });
1663
1707
  files.forEach((filename) => {
1664
1708
  const filePath = path5.join(modulePath, filename);
@@ -1757,9 +1801,9 @@ class ScanInfo {
1757
1801
  files.zone.databases.push(name);
1758
1802
  });
1759
1803
  }),
1760
- ...serviceDirs.map(async (dirname2) => {
1761
- const name = dirname2.slice(1);
1762
- const filenames = await exec.readdir(path5.join("lib", dirname2));
1804
+ ...serviceDirs.map(async (dirname) => {
1805
+ const name = dirname.slice(1);
1806
+ const filenames = await exec.readdir(path5.join("lib", dirname));
1763
1807
  filenames.forEach((filename) => {
1764
1808
  if (filename.endsWith(".dictionary.ts"))
1765
1809
  files.dictionary.services.push(name);
@@ -2328,8 +2372,13 @@ class CommandExecutionError extends Error {
2328
2372
  const displayCommand = formatCommandForDisplay(command, args);
2329
2373
  const status = signal ? `signal: ${signal}` : `exit code: ${code ?? "unknown"}`;
2330
2374
  const output = (stderr || stdout).trim();
2331
- super([`Command failed: ${displayCommand}`, `cwd: ${cwd}`, status, output ? `
2332
- ${output}` : ""].join(`
2375
+ super([
2376
+ `Command failed: ${displayCommand}`,
2377
+ `cwd: ${cwd}`,
2378
+ status,
2379
+ output ? `
2380
+ ${output}` : ""
2381
+ ].join(`
2333
2382
  `), {
2334
2383
  cause
2335
2384
  });
@@ -2378,7 +2427,13 @@ var parseEnvFile = (envPath) => {
2378
2427
  }
2379
2428
  return env;
2380
2429
  };
2381
- var PAGE_ROUTE_EXPORTS = new Set(["default", "pageConfig", "head", "generateHead", "Loading"]);
2430
+ var PAGE_ROUTE_EXPORTS = new Set([
2431
+ "default",
2432
+ "pageConfig",
2433
+ "head",
2434
+ "generateHead",
2435
+ "Loading"
2436
+ ]);
2382
2437
  var ROOT_LAYOUT_EXPORTS = new Set([
2383
2438
  "default",
2384
2439
  "head",
@@ -2391,7 +2446,12 @@ var ROOT_LAYOUT_EXPORTS = new Set([
2391
2446
  "gaTrackingId",
2392
2447
  "Loading"
2393
2448
  ]);
2394
- var LAYOUT_ROUTE_EXPORTS = new Set(["default", "head", "generateHead", "Loading"]);
2449
+ var LAYOUT_ROUTE_EXPORTS = new Set([
2450
+ "default",
2451
+ "head",
2452
+ "generateHead",
2453
+ "Loading"
2454
+ ]);
2395
2455
  function validateRouteSourceExports(source, filePath, kind, options = {}) {
2396
2456
  const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
2397
2457
  const allowed = kind === "page" ? PAGE_ROUTE_EXPORTS : options.rootLayout ? ROOT_LAYOUT_EXPORTS : LAYOUT_ROUTE_EXPORTS;
@@ -2460,16 +2520,16 @@ class Executor {
2460
2520
  linter = null;
2461
2521
  constructor(name, cwdPath) {
2462
2522
  this.name = name;
2463
- this.logger = new Logger4(name);
2523
+ this.logger = new Logger3(name);
2464
2524
  this.logs = [];
2465
2525
  this.cwdPath = cwdPath;
2466
2526
  }
2467
2527
  #stdout(data) {
2468
2528
  if (Executor.verbose)
2469
- Logger4.raw(chalk4.dim(data.toString()));
2529
+ Logger3.raw(chalk4.dim(data.toString()));
2470
2530
  }
2471
2531
  #stderr(data) {
2472
- Logger4.raw(chalk4.red(data.toString()));
2532
+ Logger3.raw(chalk4.red(data.toString()));
2473
2533
  }
2474
2534
  exec(command, options = {}) {
2475
2535
  const cwd = options.cwd?.toString() ?? this.cwdPath;
@@ -2486,11 +2546,26 @@ class Executor {
2486
2546
  });
2487
2547
  return new Promise((resolve, reject) => {
2488
2548
  proc.on("error", (error) => {
2489
- reject(new CommandExecutionError({ command, cwd, code: null, signal: null, stdout, stderr, cause: error }));
2549
+ reject(new CommandExecutionError({
2550
+ command,
2551
+ cwd,
2552
+ code: null,
2553
+ signal: null,
2554
+ stdout,
2555
+ stderr,
2556
+ cause: error
2557
+ }));
2490
2558
  });
2491
2559
  proc.on("exit", (code, signal) => {
2492
2560
  if (!!code || signal)
2493
- reject(new CommandExecutionError({ command, cwd, code, signal, stdout, stderr }));
2561
+ reject(new CommandExecutionError({
2562
+ command,
2563
+ cwd,
2564
+ code,
2565
+ signal,
2566
+ stdout,
2567
+ stderr
2568
+ }));
2494
2569
  else
2495
2570
  resolve({ code, signal });
2496
2571
  });
@@ -2498,7 +2573,7 @@ class Executor {
2498
2573
  }
2499
2574
  spawn(command, args = [], options = {}) {
2500
2575
  const cwd = options.cwd?.toString() ?? this.cwdPath;
2501
- const proc = spawn(command, args, {
2576
+ const proc = spawn2(command, args, {
2502
2577
  cwd: this.cwdPath,
2503
2578
  ...options
2504
2579
  });
@@ -2516,18 +2591,35 @@ class Executor {
2516
2591
  });
2517
2592
  return new Promise((resolve, reject) => {
2518
2593
  proc.on("error", (error) => {
2519
- reject(new CommandExecutionError({ command, args, cwd, code: null, signal: null, stdout, stderr, cause: error }));
2594
+ reject(new CommandExecutionError({
2595
+ command,
2596
+ args,
2597
+ cwd,
2598
+ code: null,
2599
+ signal: null,
2600
+ stdout,
2601
+ stderr,
2602
+ cause: error
2603
+ }));
2520
2604
  });
2521
2605
  proc.on("close", (code, signal) => {
2522
2606
  if (code !== 0 || signal)
2523
- reject(new CommandExecutionError({ command, args, cwd, code, signal, stdout, stderr }));
2607
+ reject(new CommandExecutionError({
2608
+ command,
2609
+ args,
2610
+ cwd,
2611
+ code,
2612
+ signal,
2613
+ stdout,
2614
+ stderr
2615
+ }));
2524
2616
  else
2525
2617
  resolve(stdout);
2526
2618
  });
2527
2619
  });
2528
2620
  }
2529
2621
  spawnSync(command, args = [], options = {}) {
2530
- const proc = spawn(command, args, {
2622
+ const proc = spawn2(command, args, {
2531
2623
  cwd: this.cwdPath,
2532
2624
  ...options
2533
2625
  });
@@ -2564,7 +2656,15 @@ class Executor {
2564
2656
  });
2565
2657
  proc.on("exit", (code, signal) => {
2566
2658
  if (!!code || signal)
2567
- reject(new CommandExecutionError({ command: modulePath, args, cwd, code, signal, stdout, stderr }));
2659
+ reject(new CommandExecutionError({
2660
+ command: modulePath,
2661
+ args,
2662
+ cwd,
2663
+ code,
2664
+ signal,
2665
+ stdout,
2666
+ stderr
2667
+ }));
2568
2668
  else
2569
2669
  resolve({ code, signal });
2570
2670
  });
@@ -2651,7 +2751,7 @@ class Executor {
2651
2751
  contentStr = currentContent;
2652
2752
  } else {
2653
2753
  await FileSys.writeText(writePath, contentStr);
2654
- if (Logger4.isVerbose())
2754
+ if (Logger3.isVerbose())
2655
2755
  this.logger.rawLog(chalk4.yellow(`File Update: ${filePath}`));
2656
2756
  }
2657
2757
  } else {
@@ -2698,7 +2798,11 @@ class Executor {
2698
2798
  this.logger.debug(msg);
2699
2799
  return this;
2700
2800
  }
2701
- spinning(msg, { prefix = `${this.emoji}${this.name}`, indent = 0, enableSpin = !Executor.verbose } = {}) {
2801
+ spinning(msg, {
2802
+ prefix = `${this.emoji}${this.name}`,
2803
+ indent = 0,
2804
+ enableSpin = !Executor.verbose
2805
+ } = {}) {
2702
2806
  return new Spinner(msg, { prefix, indent, enableSpin }).start();
2703
2807
  }
2704
2808
  #tsconfig = null;
@@ -2711,7 +2815,10 @@ class Executor {
2711
2815
  const result = {
2712
2816
  ...extendsTsconfig,
2713
2817
  ...tsconfig,
2714
- compilerOptions: { ...extendsTsconfig.compilerOptions, ...tsconfig.compilerOptions }
2818
+ compilerOptions: {
2819
+ ...extendsTsconfig.compilerOptions,
2820
+ ...tsconfig.compilerOptions
2821
+ }
2715
2822
  };
2716
2823
  this.#tsconfig = result;
2717
2824
  return result;
@@ -2724,7 +2831,9 @@ class Executor {
2724
2831
  this.#tsconfig = tsconfig;
2725
2832
  }
2726
2833
  #packageJson = null;
2727
- async getPackageJson({ refresh } = {}) {
2834
+ async getPackageJson({
2835
+ refresh
2836
+ } = {}) {
2728
2837
  if (this.#packageJson && !refresh)
2729
2838
  return this.#packageJson;
2730
2839
  const packageJson = await this.readJson("package.json");
@@ -2757,8 +2866,8 @@ class Executor {
2757
2866
  return null;
2758
2867
  const filename = typeof result === "object" ? result.filename : path7.basename(targetPath).replace(".js", ".ts");
2759
2868
  const content = typeof result === "object" ? result.content : result;
2760
- const dirname3 = path7.dirname(targetPath);
2761
- const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${dirname3}/${filename}`);
2869
+ const dirname2 = path7.dirname(targetPath);
2870
+ const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${dirname2}/${filename}`);
2762
2871
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2763
2872
  return this.writeFile(convertedTargetPath, content, { overwrite });
2764
2873
  } else if (targetPath.endsWith(".template")) {
@@ -2766,13 +2875,15 @@ class Executor {
2766
2875
  const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath.slice(0, -9));
2767
2876
  const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
2768
2877
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2769
- return this.writeFile(convertedTargetPath, convertedContent, { overwrite });
2878
+ return this.writeFile(convertedTargetPath, convertedContent, {
2879
+ overwrite
2880
+ });
2770
2881
  } else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
2771
2882
  const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
2772
2883
  const writePath = this.getPath(convertedTargetPath);
2773
- const dirname3 = path7.dirname(writePath);
2774
- if (!await FileSys.dirExists(dirname3))
2775
- await mkdir2(dirname3, { recursive: true });
2884
+ const dirname2 = path7.dirname(writePath);
2885
+ if (!await FileSys.dirExists(dirname2))
2886
+ await mkdir2(dirname2, { recursive: true });
2776
2887
  await copyFile(templatePath, writePath);
2777
2888
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2778
2889
  return { filePath: writePath, content: "" };
@@ -2792,14 +2903,24 @@ class Executor {
2792
2903
  const prefixTemplatePath = templatePath;
2793
2904
  if ((await stat2(prefixTemplatePath)).isFile()) {
2794
2905
  const filename = path7.basename(prefixTemplatePath);
2795
- const fileContent = await this.#applyTemplateFile({ templatePath: prefixTemplatePath, targetPath: path7.join(basePath2, filename), scanInfo, overwrite }, dict, options);
2906
+ const fileContent = await this.#applyTemplateFile({
2907
+ templatePath: prefixTemplatePath,
2908
+ targetPath: path7.join(basePath2, filename),
2909
+ scanInfo,
2910
+ overwrite
2911
+ }, dict, options);
2796
2912
  return fileContent ? [fileContent] : [];
2797
2913
  } else {
2798
2914
  const subdirs = await readDirEntries(templatePath);
2799
2915
  const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
2800
2916
  const subpath = path7.join(templatePath, subdir);
2801
2917
  if ((await stat2(subpath)).isFile()) {
2802
- const fileContent = await this.#applyTemplateFile({ templatePath: subpath, targetPath: path7.join(basePath2, subdir), scanInfo, overwrite }, dict, options);
2918
+ const fileContent = await this.#applyTemplateFile({
2919
+ templatePath: subpath,
2920
+ targetPath: path7.join(basePath2, subdir),
2921
+ scanInfo,
2922
+ overwrite
2923
+ }, dict, options);
2803
2924
  return fileContent ? [fileContent] : [];
2804
2925
  } else
2805
2926
  return await this._applyTemplate({
@@ -2828,7 +2949,10 @@ class Executor {
2828
2949
  async applyTemplate(options) {
2829
2950
  const dict = {
2830
2951
  ...options.dict ?? {},
2831
- ...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [capitalize(key), capitalize(value)]))
2952
+ ...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
2953
+ capitalize(key),
2954
+ capitalize(value)
2955
+ ]))
2832
2956
  };
2833
2957
  return this._applyTemplate({ ...options, dict });
2834
2958
  }
@@ -2843,6 +2967,48 @@ class Executor {
2843
2967
  const message = typeChecker.formatDiagnostics(fileDiagnostics);
2844
2968
  return { fileDiagnostics, fileErrors, fileWarnings, message };
2845
2969
  }
2970
+ async typeCheckAsync(filePath) {
2971
+ const path8 = this.getPath(filePath);
2972
+ const entry = await this.#resolveTypecheckWorkerEntry();
2973
+ const proc = Bun.spawn([process.execPath, entry], {
2974
+ cwd: this.cwdPath,
2975
+ env: {
2976
+ ...process.env,
2977
+ AKAN_TYPECHECK_CWD: this.cwdPath,
2978
+ AKAN_TYPECHECK_FILE: path8
2979
+ },
2980
+ stdout: "pipe",
2981
+ stderr: "pipe"
2982
+ });
2983
+ const [stdout, stderr, exitCode] = await Promise.all([
2984
+ new Response(proc.stdout).text(),
2985
+ new Response(proc.stderr).text(),
2986
+ proc.exited
2987
+ ]);
2988
+ if (exitCode !== 0)
2989
+ throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
2990
+ const result = JSON.parse(stdout);
2991
+ return {
2992
+ fileDiagnostics: Array.from({ length: result.fileDiagnosticsCount }),
2993
+ fileErrors: Array.from({ length: result.fileErrorsCount }),
2994
+ fileWarnings: Array.from({ length: result.fileWarningsCount }),
2995
+ message: result.message
2996
+ };
2997
+ }
2998
+ async#resolveTypecheckWorkerEntry() {
2999
+ const dirname2 = getDirname(import.meta.url);
3000
+ const candidates = [
3001
+ path7.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
3002
+ path7.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
3003
+ path7.join(dirname2, "typecheck/typecheck.proc.ts"),
3004
+ path7.join(dirname2, "typecheck.proc.js"),
3005
+ path7.join(dirname2, "typecheck.proc.ts")
3006
+ ];
3007
+ for (const candidate of candidates)
3008
+ if (await Bun.file(candidate).exists())
3009
+ return candidate;
3010
+ throw new Error(`[devkit] typecheck worker entry not found; looked in: ${candidates.join(", ")}`);
3011
+ }
2846
3012
  getLinter() {
2847
3013
  this.linter ??= new Linter(this.cwdPath);
2848
3014
  return this.linter;
@@ -2850,7 +3016,10 @@ class Executor {
2850
3016
  async lint(filePath, { fix = false, dryRun = false } = {}) {
2851
3017
  const path8 = this.getPath(filePath);
2852
3018
  const linter = this.getLinter();
2853
- const { results, errors, warnings } = await linter.lint(path8, { fix, dryRun });
3019
+ const { results, errors, warnings } = await linter.lint(path8, {
3020
+ fix,
3021
+ dryRun
3022
+ });
2854
3023
  const message = linter.formatLintResults(results);
2855
3024
  return { results, message, errors, warnings };
2856
3025
  }
@@ -2876,6 +3045,7 @@ class WorkspaceExecutor extends Executor {
2876
3045
  const sourceEnv = envPath ? { ...process.env, ...parseEnvFile(envPath) } : process.env;
2877
3046
  const appName = sourceEnv.AKAN_PUBLIC_APP_NAME;
2878
3047
  const workspaceRoot = sourceEnv.AKAN_WORKSPACE_ROOT;
3048
+ const workspaceId = sourceEnv.AKAN_WORKSPACE_ID;
2879
3049
  const repoName = sourceEnv.AKAN_PUBLIC_REPO_NAME;
2880
3050
  if (!repoName)
2881
3051
  throw new Error("AKAN_PUBLIC_REPO_NAME is not set");
@@ -2886,7 +3056,23 @@ class WorkspaceExecutor extends Executor {
2886
3056
  const env = sourceEnv.AKAN_PUBLIC_ENV ?? "debug";
2887
3057
  if (!env)
2888
3058
  throw new Error("AKAN_PUBLIC_ENV is not set");
2889
- return { ...appName ? { appName } : {}, workspaceRoot, repoName, serveDomain, env, portOffset };
3059
+ return {
3060
+ ...appName ? { appName } : {},
3061
+ workspaceRoot,
3062
+ repoName,
3063
+ serveDomain,
3064
+ env,
3065
+ portOffset,
3066
+ workspaceId
3067
+ };
3068
+ }
3069
+ getWorkspaceId({
3070
+ allowEmpty
3071
+ } = {}) {
3072
+ const { workspaceId } = WorkspaceExecutor.getBaseDevEnv();
3073
+ if (!workspaceId && !allowEmpty)
3074
+ throw new Error("Workspace ID is not found");
3075
+ return workspaceId;
2890
3076
  }
2891
3077
  async scan() {
2892
3078
  return await WorkspaceInfo.fromExecutor(this);
@@ -2902,7 +3088,10 @@ class WorkspaceExecutor extends Executor {
2902
3088
  return await this.#getDirHasFile(`${this.workspaceRoot}/libs`, "akan.config.ts");
2903
3089
  }
2904
3090
  async getSyss() {
2905
- const [appNames, libNames] = await Promise.all([this.getApps(), this.getLibs()]);
3091
+ const [appNames, libNames] = await Promise.all([
3092
+ this.getApps(),
3093
+ this.getLibs()
3094
+ ]);
2906
3095
  return [appNames, libNames];
2907
3096
  }
2908
3097
  async getPkgs() {
@@ -2911,7 +3100,11 @@ class WorkspaceExecutor extends Executor {
2911
3100
  return await this.#getDirHasFile(`${this.workspaceRoot}/pkgs`, "package.json");
2912
3101
  }
2913
3102
  async getExecs() {
2914
- const [appNames, libNames, pkgNames] = await Promise.all([this.getApps(), this.getLibs(), this.getPkgs()]);
3103
+ const [appNames, libNames, pkgNames] = await Promise.all([
3104
+ this.getApps(),
3105
+ this.getLibs(),
3106
+ this.getPkgs()
3107
+ ]);
2915
3108
  return [appNames, libNames, pkgNames];
2916
3109
  }
2917
3110
  async setPkgTsPaths(name) {
@@ -2929,7 +3122,10 @@ class WorkspaceExecutor extends Executor {
2929
3122
  async unsetPkgTsPaths(name) {
2930
3123
  const rootTsConfig = await this.readJson("tsconfig.json");
2931
3124
  const filteredKeys = Object.keys(rootTsConfig.compilerOptions.paths ?? {}).filter((key) => key !== name && key !== `${name}/*`);
2932
- rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [key, rootTsConfig.compilerOptions.paths?.[key] ?? []]));
3125
+ rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [
3126
+ key,
3127
+ rootTsConfig.compilerOptions.paths?.[key] ?? []
3128
+ ]));
2933
3129
  if (rootTsConfig.references) {
2934
3130
  rootTsConfig.references = rootTsConfig.references.filter((ref) => ref.path !== `./pkgs/${name}/tsconfig.json`);
2935
3131
  }
@@ -2938,12 +3134,12 @@ class WorkspaceExecutor extends Executor {
2938
3134
  }
2939
3135
  async getDirInModule(basePath2, name) {
2940
3136
  const AVOID_DIRS = ["__lib", "__scalar", `_`, `_${name}`];
2941
- const getDirs = async (dirname3, maxDepth = 3, results = [], prefix = "") => {
2942
- const dirs = await this.readdir(dirname3);
3137
+ const getDirs = async (dirname2, maxDepth = 3, results = [], prefix = "") => {
3138
+ const dirs = await this.readdir(dirname2);
2943
3139
  await Promise.all(dirs.map(async (dir) => {
2944
3140
  if (dir.includes("_") || AVOID_DIRS.includes(dir))
2945
3141
  return;
2946
- const dirPath = path7.join(dirname3, dir);
3142
+ const dirPath = path7.join(dirname2, dir);
2947
3143
  if ((await stat2(dirPath)).isDirectory()) {
2948
3144
  results.push(`${prefix}${dir}`);
2949
3145
  if (maxDepth > 0)
@@ -2963,12 +3159,12 @@ class WorkspaceExecutor extends Executor {
2963
3159
  }
2964
3160
  async#getDirHasFile(basePath2, targetFilename) {
2965
3161
  const AVOID_DIRS = ["node_modules", "dist", "public", "webkit"];
2966
- const getDirs = async (dirname3, maxDepth = 3, results = [], prefix = "") => {
2967
- const dirs = await this.readdir(dirname3);
3162
+ const getDirs = async (dirname2, maxDepth = 3, results = [], prefix = "") => {
3163
+ const dirs = await this.readdir(dirname2);
2968
3164
  await Promise.all(dirs.map(async (dir) => {
2969
3165
  if (AVOID_DIRS.includes(dir))
2970
3166
  return;
2971
- const dirPath = path7.join(dirname3, dir);
3167
+ const dirPath = path7.join(dirname2, dir);
2972
3168
  if ((await stat2(dirPath)).isDirectory()) {
2973
3169
  const hasTargetFile = await FileSys.fileExists(path7.join(dirPath, targetFilename));
2974
3170
  if (hasTargetFile)
@@ -3021,7 +3217,11 @@ class SysExecutor extends Executor {
3021
3217
  name;
3022
3218
  type;
3023
3219
  emoji;
3024
- constructor({ workspace = WorkspaceExecutor.fromRoot(), name, type }) {
3220
+ constructor({
3221
+ workspace = WorkspaceExecutor.fromRoot(),
3222
+ name,
3223
+ type
3224
+ }) {
3025
3225
  super(name, `${workspace.workspaceRoot}/${type}s/${name}`);
3026
3226
  this.workspace = workspace;
3027
3227
  this.name = name;
@@ -3090,7 +3290,11 @@ class SysExecutor extends Executor {
3090
3290
  } = {}) {
3091
3291
  if (this.#scanInfo && !refresh)
3092
3292
  return this.#scanInfo;
3093
- const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, { refresh }) : await LibInfo.fromExecutor(this, { refresh });
3293
+ const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, {
3294
+ refresh
3295
+ }) : await LibInfo.fromExecutor(this, {
3296
+ refresh
3297
+ });
3094
3298
  if (write) {
3095
3299
  await Promise.all(this.#getScanTemplateTasks(scanInfo));
3096
3300
  await this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
@@ -3120,7 +3324,10 @@ class SysExecutor extends Executor {
3120
3324
  },
3121
3325
  devDependencies: {
3122
3326
  ...Object.fromEntries(Object.entries(libPackageJson.devDependencies ?? {}).filter(([dep]) => !dependencySet.has(dep))),
3123
- ...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.devDependencies?.[dep] ?? rootPackageJson.dependencies?.[dep]]))
3327
+ ...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [
3328
+ dep,
3329
+ rootPackageJson.devDependencies?.[dep] ?? rootPackageJson.dependencies?.[dep]
3330
+ ]))
3124
3331
  }
3125
3332
  };
3126
3333
  await this.setPackageJson(libPkgJsonWithDeps);
@@ -3187,7 +3394,11 @@ class SysExecutor extends Executor {
3187
3394
  ...await LibExecutor.from(this, lib).getConstantFiles(),
3188
3395
  ...await LibExecutor.from(this, lib).getScalarConstantFiles()
3189
3396
  ]));
3190
- return [...sysContantFiles, ...sysScalarConstantFiles, ...libConstantFiles.flat()];
3397
+ return [
3398
+ ...sysContantFiles,
3399
+ ...sysScalarConstantFiles,
3400
+ ...libConstantFiles.flat()
3401
+ ];
3191
3402
  }
3192
3403
  async getDictionaryFiles() {
3193
3404
  const modules = await this.getModules();
@@ -3196,10 +3407,17 @@ class SysExecutor extends Executor {
3196
3407
  async applyTemplate(options) {
3197
3408
  const dict = {
3198
3409
  ...options.dict ?? {},
3199
- ...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [capitalize(key), capitalize(value)]))
3410
+ ...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
3411
+ capitalize(key),
3412
+ capitalize(value)
3413
+ ]))
3200
3414
  };
3201
3415
  const scanInfo = await this.scan();
3202
- const fileContents = await this._applyTemplate({ ...options, scanInfo, dict });
3416
+ const fileContents = await this._applyTemplate({
3417
+ ...options,
3418
+ scanInfo,
3419
+ dict
3420
+ });
3203
3421
  await this.scan();
3204
3422
  return fileContents;
3205
3423
  }
@@ -3251,7 +3469,10 @@ class AppExecutor extends SysExecutor {
3251
3469
  if (type === "build") {
3252
3470
  if (await this.exists(this.dist.cwdPath))
3253
3471
  await this.dist.exec(`rm -rf ${this.dist.cwdPath}`);
3254
- await Promise.all([this.dist.mkdir("private"), this.dist.mkdir("public")]);
3472
+ await Promise.all([
3473
+ this.dist.mkdir("private"),
3474
+ this.dist.mkdir("public")
3475
+ ]);
3255
3476
  await Promise.all([
3256
3477
  this.cp("private", `${this.dist.cwdPath}/private`),
3257
3478
  this.cp("public", `${this.dist.cwdPath}/public`)
@@ -3294,7 +3515,9 @@ class AppExecutor extends SysExecutor {
3294
3515
  return this.#akanConfig;
3295
3516
  }
3296
3517
  #pageKeys = null;
3297
- async getPageKeys({ refresh } = {}) {
3518
+ async getPageKeys({
3519
+ refresh
3520
+ } = {}) {
3298
3521
  if (this.#pageKeys && !refresh)
3299
3522
  return this.#pageKeys;
3300
3523
  const akanConfig2 = await this.getConfig();
@@ -3305,7 +3528,11 @@ class AppExecutor extends SysExecutor {
3305
3528
  this.#pageKeys = [];
3306
3529
  return this.#pageKeys;
3307
3530
  }
3308
- for await (const rel of glob.scan({ cwd: pageDir, absolute: false, onlyFiles: true })) {
3531
+ for await (const rel of glob.scan({
3532
+ cwd: pageDir,
3533
+ absolute: false,
3534
+ onlyFiles: true
3535
+ })) {
3309
3536
  const segments = rel.split(path7.sep);
3310
3537
  if (segments.some((s) => s === "node_modules"))
3311
3538
  continue;
@@ -3315,7 +3542,10 @@ class AppExecutor extends SysExecutor {
3315
3542
  if (!isRouteSourceFile(posix))
3316
3543
  continue;
3317
3544
  const key = `./${posix}`;
3318
- validateSubRoutePageKey(key, akanConfig2.basePaths, { appName: this.name, filePath: absPath });
3545
+ validateSubRoutePageKey(key, akanConfig2.basePaths, {
3546
+ appName: this.name,
3547
+ filePath: absPath
3548
+ });
3319
3549
  const parsed = parseRouteModuleKey(key);
3320
3550
  if (parsed.isInternalRootLayout) {
3321
3551
  throw new Error(`[route-convention] __root_layout is reserved for Akan.js generated root layout: ${absPath}`);
@@ -3336,7 +3566,10 @@ class AppExecutor extends SysExecutor {
3336
3566
  const projectAssetsPath = `${this.cwdPath}/private`;
3337
3567
  const projectPublicLibPath = `${projectPublicPath}/libs`;
3338
3568
  const projectAssetsLibPath = `${projectAssetsPath}/libs`;
3339
- await Promise.all([this.removeDir(projectPublicLibPath), this.removeDir(projectAssetsLibPath)]);
3569
+ await Promise.all([
3570
+ this.removeDir(projectPublicLibPath),
3571
+ this.removeDir(projectAssetsLibPath)
3572
+ ]);
3340
3573
  const targetPublicDeps = [];
3341
3574
  for (const dep of libDeps) {
3342
3575
  if (await this.exists(`${this.workspace.workspaceRoot}/libs/${dep}/public`))
@@ -3354,8 +3587,15 @@ class AppExecutor extends SysExecutor {
3354
3587
  ...targetAssetsDeps.map((dep) => this.cp(`${this.workspace.workspaceRoot}/libs/${dep}/private`, `${projectAssetsLibPath}/${dep}`))
3355
3588
  ]);
3356
3589
  }
3357
- async scanSync({ refresh = false, write = true } = {}) {
3358
- const scanInfo = await this.scan({ refresh, write, writeLib: write });
3590
+ async scanSync({
3591
+ refresh = false,
3592
+ write = true
3593
+ } = {}) {
3594
+ const scanInfo = await this.scan({
3595
+ refresh,
3596
+ write,
3597
+ writeLib: write
3598
+ });
3359
3599
  if (write)
3360
3600
  await this.syncAssets(scanInfo.getScanResult().libDeps);
3361
3601
  return scanInfo;
@@ -3399,7 +3639,10 @@ class PkgExecutor extends Executor {
3399
3639
  name;
3400
3640
  dist;
3401
3641
  emoji = execEmoji.pkg;
3402
- constructor({ workspace = WorkspaceExecutor.fromRoot(), name }) {
3642
+ constructor({
3643
+ workspace = WorkspaceExecutor.fromRoot(),
3644
+ name
3645
+ }) {
3403
3646
  super(name, `${workspace.workspaceRoot}/pkgs/${name}`);
3404
3647
  this.workspace = workspace;
3405
3648
  this.name = name;
@@ -3419,7 +3662,10 @@ class PkgExecutor extends Executor {
3419
3662
  return scanInfo;
3420
3663
  }
3421
3664
  async#getDependencyVersion(rootPackageJson, dep) {
3422
- const rootDeps = { ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies };
3665
+ const rootDeps = {
3666
+ ...rootPackageJson.dependencies,
3667
+ ...rootPackageJson.devDependencies
3668
+ };
3423
3669
  const rootVersion = rootDeps[dep];
3424
3670
  if (rootVersion)
3425
3671
  return rootVersion;
@@ -3460,7 +3706,10 @@ class PkgExecutor extends Executor {
3460
3706
  };
3461
3707
  }
3462
3708
  async updatePackageJsonDependencies(dependencies = [], devDependencies = []) {
3463
- const [rootPackageJson, pkgJson] = await Promise.all([this.workspace.getPackageJson(), this.getPackageJson()]);
3709
+ const [rootPackageJson, pkgJson] = await Promise.all([
3710
+ this.workspace.getPackageJson(),
3711
+ this.getPackageJson()
3712
+ ]);
3464
3713
  const dependencyMaps = await this.#toDependencyMap(rootPackageJson, dependencies, devDependencies);
3465
3714
  const newPkgJson = {
3466
3715
  ...pkgJson,
@@ -3470,16 +3719,29 @@ class PkgExecutor extends Executor {
3470
3719
  return newPkgJson;
3471
3720
  }
3472
3721
  async generateDistPackageJson(dependencies = [], devDependencies = []) {
3473
- const [rootPackageJson, pkgJson] = await Promise.all([this.workspace.getPackageJson(), this.getPackageJson()]);
3722
+ const [rootPackageJson, pkgJson] = await Promise.all([
3723
+ this.workspace.getPackageJson(),
3724
+ this.getPackageJson()
3725
+ ]);
3474
3726
  const dependencyMaps = await this.#toDependencyMap(rootPackageJson, dependencies, devDependencies);
3475
3727
  const distPkgJson = {
3476
3728
  ...pkgJson,
3477
3729
  type: "module",
3478
- exports: { ...pkgJson.exports, ".": { import: "./index.ts", types: "./index.ts", default: "./index.ts" } },
3730
+ exports: {
3731
+ ...pkgJson.exports,
3732
+ ".": {
3733
+ import: "./index.ts",
3734
+ types: "./index.ts",
3735
+ default: "./index.ts"
3736
+ }
3737
+ },
3479
3738
  engines: { bun: ">=1.3.13" },
3480
3739
  ...dependencyMaps
3481
3740
  };
3482
- await Promise.all([this.dist.writeJson("package.json", distPkgJson), this.writeJson("package.json", distPkgJson)]);
3741
+ await Promise.all([
3742
+ this.dist.writeJson("package.json", distPkgJson),
3743
+ this.writeJson("package.json", distPkgJson)
3744
+ ]);
3483
3745
  return distPkgJson;
3484
3746
  }
3485
3747
  async build() {
@@ -3492,7 +3754,10 @@ class PkgExecutor extends Executor {
3492
3754
  await this.cp(`${this.cwdPath}/dist`, this.dist.cwdPath);
3493
3755
  }
3494
3756
  async generateTsconfigJson() {
3495
- const [rootTsconfig, pkgTsconfig] = await Promise.all([this.workspace.getTsConfig(), this.getTsConfig()]);
3757
+ const [rootTsconfig, pkgTsconfig] = await Promise.all([
3758
+ this.workspace.getTsConfig(),
3759
+ this.getTsConfig()
3760
+ ]);
3496
3761
  const tsconfig = {
3497
3762
  ...rootTsconfig,
3498
3763
  ...pkgTsconfig,
@@ -3656,7 +3921,7 @@ var createTunnel = async (service, { app, environment, port = service === "postg
3656
3921
 
3657
3922
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.host.ts
3658
3923
  import path8 from "path";
3659
- import { Logger as Logger5 } from "akanjs/common";
3924
+ import { Logger as Logger4 } from "akanjs/common";
3660
3925
  var builderMsgTypeSet = new Set([
3661
3926
  "build-route-res",
3662
3927
  "builder-ready",
@@ -3668,7 +3933,7 @@ var builderMsgTypeSet = new Set([
3668
3933
  class IncrementalBuilderHost {
3669
3934
  static #restartBaseDelayMs = 1000;
3670
3935
  static #restartMaxDelayMs = 30000;
3671
- logger = new Logger5("IncrementalBuilderHost");
3936
+ logger = new Logger4("IncrementalBuilderHost");
3672
3937
  entry;
3673
3938
  env;
3674
3939
  app;
@@ -3916,7 +4181,7 @@ class BackendImportGraph {
3916
4181
 
3917
4182
  class AkanAppHost {
3918
4183
  app;
3919
- logger = new Logger6("AkanAppHost");
4184
+ logger = new Logger5("AkanAppHost");
3920
4185
  withInk;
3921
4186
  env;
3922
4187
  #backend = null;
@@ -4199,19 +4464,19 @@ class AkanAppHost {
4199
4464
  }
4200
4465
  }
4201
4466
  // pkgs/@akanjs/devkit/applicationBuildReporter.ts
4202
- import { Logger as Logger7 } from "akanjs/common";
4467
+ import { Logger as Logger6 } from "akanjs/common";
4203
4468
 
4204
4469
  class ApplicationBuildReporter {
4205
4470
  static create() {
4206
4471
  return {
4207
- phaseDone: (phase) => Logger7.rawLog(ApplicationBuildReporter.formatPhaseLine(phase))
4472
+ phaseDone: (phase) => Logger6.rawLog(ApplicationBuildReporter.formatPhaseLine(phase))
4208
4473
  };
4209
4474
  }
4210
4475
  static printSummary(result) {
4211
- Logger7.rawLog("");
4212
- Logger7.rawLog(`Route artifacts: ${result.artifactDir}`);
4213
- Logger7.rawLog(`Server output: ${result.outputDir}`);
4214
- Logger7.rawLog(`Done in ${ApplicationBuildReporter.formatDuration(result.durationMs)}`);
4476
+ Logger6.rawLog("");
4477
+ Logger6.rawLog(`Route artifacts: ${result.artifactDir}`);
4478
+ Logger6.rawLog(`Server output: ${result.outputDir}`);
4479
+ Logger6.rawLog(`Done in ${ApplicationBuildReporter.formatDuration(result.durationMs)}`);
4215
4480
  }
4216
4481
  static formatError(error) {
4217
4482
  if (error instanceof AggregateError) {
@@ -4510,13 +4775,13 @@ import path14 from "path";
4510
4775
 
4511
4776
  // pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
4512
4777
  import path12 from "path";
4513
- import { Logger as Logger8 } from "akanjs/common";
4778
+ import { Logger as Logger7 } from "akanjs/common";
4514
4779
  var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
4515
4780
  var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
4516
4781
  var CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
4517
4782
 
4518
4783
  class BarrelAnalyzer {
4519
- #logger = new Logger8("BarrelAnalyzer");
4784
+ #logger = new Logger7("BarrelAnalyzer");
4520
4785
  #opts;
4521
4786
  #cache = new Map;
4522
4787
  #tsTranspiler = new Bun.Transpiler({ loader: "ts" });
@@ -6216,7 +6481,7 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
6216
6481
  }
6217
6482
  // pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
6218
6483
  import path23 from "path";
6219
- import { Logger as Logger9 } from "akanjs/common";
6484
+ import { Logger as Logger8 } from "akanjs/common";
6220
6485
  import { compile } from "tailwindcss";
6221
6486
 
6222
6487
  // pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
@@ -6361,7 +6626,7 @@ var NODE_MODULES_RE3 = /[\\/]node_modules[\\/]/;
6361
6626
  var AKANJS_NODE_MODULE_RE3 = /[\\/]node_modules[\\/]akanjs[\\/]/;
6362
6627
 
6363
6628
  class CssCompiler {
6364
- #logger = new Logger9("CssCompiler");
6629
+ #logger = new Logger8("CssCompiler");
6365
6630
  #transpiler = new Bun.Transpiler({ loader: "tsx" });
6366
6631
  #app;
6367
6632
  #cssImportResolver = null;
@@ -7769,7 +8034,7 @@ class ApplicationBuildRunner {
7769
8034
  import { cp, mkdir as mkdir8, rm as rm3 } from "fs/promises";
7770
8035
 
7771
8036
  // pkgs/@akanjs/devkit/uploadRelease.ts
7772
- import { HttpClient, Logger as Logger10 } from "akanjs/common";
8037
+ import { HttpClient as HttpClient2, Logger as Logger9 } from "akanjs/common";
7773
8038
  var spinning = (message) => {
7774
8039
  const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
7775
8040
  return spinner;
@@ -7782,9 +8047,9 @@ var uploadRelease = async (appName, {
7782
8047
  os,
7783
8048
  local
7784
8049
  }) => {
7785
- const logger = new Logger10("uploadRelease");
8050
+ const logger = new Logger9("uploadRelease");
7786
8051
  const basePath2 = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
7787
- const httpClient = new HttpClient(basePath2);
8052
+ const httpClient = new HttpClient2(basePath2);
7788
8053
  const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
7789
8054
  const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
7790
8055
  const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
@@ -8768,7 +9033,7 @@ var Workspace = createInternalArgToken("Workspace");
8768
9033
  // pkgs/@akanjs/devkit/commandDecorators/command.ts
8769
9034
  import path36 from "path";
8770
9035
  import { confirm, input as input2, select as select2 } from "@inquirer/prompts";
8771
- import { Logger as Logger11 } from "akanjs/common";
9036
+ import { Logger as Logger10 } from "akanjs/common";
8772
9037
  import chalk6 from "chalk";
8773
9038
  import { program } from "commander";
8774
9039
 
@@ -9053,7 +9318,7 @@ var printCliError = (error) => {
9053
9318
  if (loggedCliErrorMessages.has(message))
9054
9319
  return;
9055
9320
  loggedCliErrorMessages.add(message);
9056
- Logger11.rawLog(`
9321
+ Logger10.rawLog(`
9057
9322
  ${chalk6.red(message)}`);
9058
9323
  };
9059
9324
  var handleOption = (programCommand, argMeta) => {
@@ -9282,7 +9547,7 @@ var runCommands = async (...commands) => {
9282
9547
  const hasCommand = process.argv.length > 2 && !process.argv[2]?.startsWith("-");
9283
9548
  if (hasHelpFlag || !hasCommand) {
9284
9549
  if (process.argv.length === 2 || process.argv.length === 3 && hasHelpFlag) {
9285
- Logger11.rawLog(formatHelp(commands, process.env.AKAN_VERSION));
9550
+ Logger10.rawLog(formatHelp(commands, process.env.AKAN_VERSION));
9286
9551
  process.exit(0);
9287
9552
  }
9288
9553
  }
@@ -9291,7 +9556,7 @@ var runCommands = async (...commands) => {
9291
9556
  });
9292
9557
  const installedAkanPackageJson = await FileSys.fileExists("./node_modules/akanjs/package.json") ? await FileSys.readJson("./node_modules/akanjs/package.json") : null;
9293
9558
  if (installedAkanPackageJson && installedAkanPackageJson.version !== process.env.AKAN_VERSION) {
9294
- Logger11.rawLog(chalk6.yellow(`
9559
+ Logger10.rawLog(chalk6.yellow(`
9295
9560
  Akan CLI version is mismatch with installed package. ${process.env.AKAN_VERSION} (global) vs ${installedAkanPackageJson.version} (akanjs)
9296
9561
  It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`));
9297
9562
  }
@@ -9327,7 +9592,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
9327
9592
  return formatCommandHelp(command, targetMeta.key);
9328
9593
  };
9329
9594
  programCommand.action(async (...args) => {
9330
- Logger11.rawLog();
9595
+ Logger10.rawLog();
9331
9596
  const cmdArgs = args.slice(0, args.length - 2);
9332
9597
  const opt = args[args.length - 2];
9333
9598
  const commandArgs = [];
@@ -9351,7 +9616,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
9351
9616
  const cmd = CommandContainer.get(command);
9352
9617
  try {
9353
9618
  await targetMeta.handler.call(cmd, ...commandArgs);
9354
- Logger11.rawLog();
9619
+ Logger10.rawLog();
9355
9620
  } catch (e) {
9356
9621
  printCliError(e);
9357
9622
  throw e;
@@ -9691,8 +9956,11 @@ import fsPromise from "fs/promises";
9691
9956
  import { input as input3, select as select3 } from "@inquirer/prompts";
9692
9957
  class Prompter {
9693
9958
  static async#getGuidelineRoot() {
9694
- const dirname3 = getDirname(import.meta.url);
9695
- const candidates = [`${dirname3}/guidelines`, `${dirname3}/../cli/guidelines`];
9959
+ const dirname2 = getDirname(import.meta.url);
9960
+ const candidates = [
9961
+ `${dirname2}/guidelines`,
9962
+ `${dirname2}/../cli/guidelines`
9963
+ ];
9696
9964
  for (const candidate of candidates) {
9697
9965
  try {
9698
9966
  await fsPromise.access(candidate);
@@ -9704,7 +9972,10 @@ class Prompter {
9704
9972
  static async selectGuideline() {
9705
9973
  const guidelineRoot = await Prompter.#getGuidelineRoot();
9706
9974
  const guideNames = (await fsPromise.readdir(guidelineRoot)).filter((name) => !name.startsWith("_"));
9707
- return await select3({ message: "Select a guideline", choices: guideNames.map((name) => ({ name, value: name })) });
9975
+ return await select3({
9976
+ message: "Select a guideline",
9977
+ choices: guideNames.map((name) => ({ name, value: name }))
9978
+ });
9708
9979
  }
9709
9980
  static async getGuideJson(guideName) {
9710
9981
  const guidelineRoot = await Prompter.#getGuidelineRoot();
@@ -9719,13 +9990,18 @@ class Prompter {
9719
9990
  return content;
9720
9991
  }
9721
9992
  static async getUpdateRequest(guideName) {
9722
- return await input3({ message: `What do you want to update in ${guideName}?` });
9993
+ return await input3({
9994
+ message: `What do you want to update in ${guideName}?`
9995
+ });
9723
9996
  }
9724
9997
  async makeTsFileUpdatePrompt({ context, request }) {
9725
9998
  return `You are a senior developer writing TypeScript-based programs using Akan.js, an in-house framework. Here's an overview of the Akan.js framework:
9726
9999
  ${await this.getDocumentation("framework")}
9727
10000
  Please understand the following background information, write code that meets the requirements, verify that it satisfies the validation conditions, and return the result.
9728
10001
 
10002
+ # Code Style
10003
+ - Use double quotes for all string literals in TypeScript/TSX code. Do not use single quotes.
10004
+
9729
10005
  # Background Information
9730
10006
  \`\`\`markdown
9731
10007
  ${context}
@@ -9771,82 +10047,11 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
9771
10047
  import { useEffect as useEffect3, useState as useState3 } from "react";
9772
10048
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9773
10049
  "use client";
9774
- // pkgs/@akanjs/devkit/cloud/cloudApi.ts
9775
- var import_dayjs = __toESM(require_dayjs_min(), 1);
9776
-
9777
- class HttpClient2 {
9778
- baseUrl;
9779
- constructor(baseUrl) {
9780
- this.baseUrl = baseUrl;
9781
- }
9782
- async get(url, { headers } = {}) {
9783
- const response = await fetch(`${this.baseUrl}${url}`, {
9784
- headers: { "Content-Type": "application/json", ...headers }
9785
- });
9786
- return response.json();
9787
- }
9788
- async post(url, data, { headers } = {}) {
9789
- const isFormData = data instanceof FormData;
9790
- const response = await fetch(`${this.baseUrl}${url}`, {
9791
- method: "POST",
9792
- body: isFormData ? data : JSON.stringify(data),
9793
- headers: isFormData ? headers : { "Content-Type": "application/json", ...headers }
9794
- });
9795
- return response.json();
9796
- }
9797
- }
9798
-
9799
- class CloudApi {
9800
- api;
9801
- #accessToken = null;
9802
- constructor(host, { accessToken } = {}) {
9803
- this.api = new HttpClient2(`${host}/api`);
9804
- this.#accessToken = accessToken ?? null;
9805
- }
9806
- async uploadEnv(devProjectId, file) {
9807
- const formData = new FormData;
9808
- formData.append("devProjectId", devProjectId);
9809
- formData.append("file", file);
9810
- const response = await this.api.post(`/uploadEnv/${devProjectId}`, formData);
9811
- return response.success;
9812
- }
9813
- async downloadEnv(devProjectId) {
9814
- const response = await this.api.get(`/downloadEnv/${devProjectId}`);
9815
- return response.success;
9816
- }
9817
- async getRemoteAuthToken(remoteId) {
9818
- if (this.#needRefreshToken())
9819
- return await this.refreshAuthToken();
9820
- else if (this.#accessToken)
9821
- return this.#accessToken;
9822
- const accessToken = await this.api.get(`/getRemoteAuthToken/${remoteId}`);
9823
- this.#accessToken = {
9824
- jwt: accessToken.jwt,
9825
- refreshToken: accessToken.refreshToken,
9826
- expiresAt: accessToken.expiresAt ? import_dayjs.default(accessToken.expiresAt) : null
9827
- };
9828
- return this.#accessToken;
9829
- }
9830
- async refreshAuthToken() {
9831
- const response = await this.api.post(`/refreshRemoteAuthToken`, {
9832
- refreshToken: this.#accessToken?.refreshToken
9833
- });
9834
- this.#accessToken = {
9835
- jwt: response.jwt,
9836
- refreshToken: response.refreshToken,
9837
- expiresAt: response.expiresAt ? import_dayjs.default(response.expiresAt) : null
9838
- };
9839
- return this.#accessToken;
9840
- }
9841
- #needRefreshToken() {
9842
- return !!this.#accessToken?.expiresAt?.isBefore(import_dayjs.default().add(1, "hour"));
9843
- }
9844
- }
9845
10050
  // pkgs/@akanjs/cli/application/application.command.ts
9846
10051
  import { select as select6 } from "@inquirer/prompts";
9847
10052
 
9848
10053
  // pkgs/@akanjs/cli/application/application.script.ts
9849
- import { Logger as Logger13 } from "akanjs/common";
10054
+ import { Logger as Logger12 } from "akanjs/common";
9850
10055
 
9851
10056
  // pkgs/@akanjs/cli/semver.ts
9852
10057
  function parseVersion(version) {
@@ -9964,14 +10169,14 @@ import { StringOutputParser } from "@langchain/core/output_parsers";
9964
10169
  import { PromptTemplate as PromptTemplate2 } from "@langchain/core/prompts";
9965
10170
  import { RunnableSequence as RunnableSequence2 } from "@langchain/core/runnables";
9966
10171
  import { ChatOpenAI as ChatOpenAI3 } from "@langchain/openai";
9967
- import { Logger as Logger12 } from "akanjs/common";
10172
+ import { Logger as Logger11 } from "akanjs/common";
9968
10173
  import ora3 from "ora";
9969
10174
 
9970
10175
  // pkgs/@akanjs/cli/openBrowser.ts
9971
- import { spawn as spawn2 } from "child_process";
10176
+ import { spawn as spawn3 } from "child_process";
9972
10177
  function openBrowser(url) {
9973
10178
  const command3 = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
9974
- const child = spawn2(command3[0], command3.slice(1), { detached: true, stdio: "ignore" });
10179
+ const child = spawn3(command3[0], command3.slice(1), { detached: true, stdio: "ignore" });
9975
10180
  child.on("error", () => {});
9976
10181
  child.unref();
9977
10182
  return Promise.resolve();
@@ -10157,7 +10362,7 @@ class ApplicationRunner extends runner("application") {
10157
10362
  return;
10158
10363
  for (const failure of failures) {
10159
10364
  const message = failure.error instanceof Error ? failure.error.message : String(failure.error);
10160
- Logger12.rawLog(`Mobile target ${failure.target} failed: ${message}`, undefined, "error");
10365
+ Logger11.rawLog(`Mobile target ${failure.target} failed: ${message}`, undefined, "error");
10161
10366
  }
10162
10367
  throw new Error(`${failures.length}/${results.length} mobile targets failed`);
10163
10368
  }
@@ -10302,18 +10507,18 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
10302
10507
  async build(app, { write = true, fast = false, quiet = false } = {}) {
10303
10508
  await app.scanSync({ write });
10304
10509
  if (!quiet)
10305
- Logger13.rawLog(`Creating an optimized production build for ${app.name}...`);
10510
+ Logger12.rawLog(`Creating an optimized production build for ${app.name}...`);
10306
10511
  try {
10307
10512
  const result = await this.applicationRunner.build(app, {
10308
10513
  fast,
10309
10514
  spinner: !quiet
10310
10515
  });
10311
- Logger13.rawLog(`${app.name} built in dist/apps/${app.name}`);
10516
+ Logger12.rawLog(`${app.name} built in dist/apps/${app.name}`);
10312
10517
  if (!quiet)
10313
10518
  ApplicationBuildReporter.printSummary(result);
10314
10519
  } catch (error) {
10315
- Logger13.rawLog(`${app.name} build failed in dist/apps/${app.name}`, undefined, "error");
10316
- Logger13.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
10520
+ Logger12.rawLog(`${app.name} build failed in dist/apps/${app.name}`, undefined, "error");
10521
+ Logger12.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
10317
10522
  throw error;
10318
10523
  }
10319
10524
  }
@@ -10325,7 +10530,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
10325
10530
  spinner2.succeed(`${app.name} typechecked`);
10326
10531
  } catch (error) {
10327
10532
  spinner2.fail(`${app.name} typecheck failed`);
10328
- Logger13.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
10533
+ Logger12.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
10329
10534
  throw error;
10330
10535
  }
10331
10536
  }
@@ -10589,11 +10794,11 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
10589
10794
  }
10590
10795
 
10591
10796
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
10592
- import { Logger as Logger16 } from "akanjs/common";
10797
+ import { Logger as Logger15 } from "akanjs/common";
10593
10798
 
10594
10799
  // pkgs/@akanjs/cli/package/package.runner.ts
10595
10800
  import path37 from "path";
10596
- import { Logger as Logger14 } from "akanjs/common";
10801
+ import { Logger as Logger13 } from "akanjs/common";
10597
10802
  var {$: $2 } = globalThis.Bun;
10598
10803
 
10599
10804
  class PackageRunner extends runner("package") {
@@ -10601,7 +10806,7 @@ class PackageRunner extends runner("package") {
10601
10806
  const pkgJson = process.env.USE_AKANJS_PKGS === "true" ? await FileSys.readJson(`${workspace?.workspaceRoot ?? process.cwd()}/pkgs/akanjs/package.json`) : await this.#getInstalledPackageJson();
10602
10807
  const version = pkgJson.name === "akanjs" ? pkgJson.version : pkgJson.dependencies?.akanjs ?? pkgJson.version;
10603
10808
  if (log)
10604
- Logger14.rawLog(`akanjs@${version}`);
10809
+ Logger13.rawLog(`akanjs@${version}`);
10605
10810
  return version;
10606
10811
  }
10607
10812
  async#getInstalledPackageJson() {
@@ -10728,8 +10933,8 @@ class PackageScript extends script("package", [PackageRunner]) {
10728
10933
 
10729
10934
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
10730
10935
  import path38 from "path";
10731
- import { confirm as confirm3 } from "@inquirer/prompts";
10732
- import { Logger as Logger15, sleep } from "akanjs/common";
10936
+ import { confirm as confirm3, input as input5, select as select7 } from "@inquirer/prompts";
10937
+ import { Logger as Logger14, sleep } from "akanjs/common";
10733
10938
  import chalk7 from "chalk";
10734
10939
  import * as QRcode from "qrcode";
10735
10940
 
@@ -10750,6 +10955,9 @@ async function getLatestPackageVersion(packageName, tag = "latest", registryUrl)
10750
10955
  }
10751
10956
 
10752
10957
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
10958
+ var addRemoteEnvServerValue = "__addRemoteEnvServer";
10959
+ var removeRemoteEnvServerValue = "__removeRemoteEnvServer";
10960
+
10753
10961
  class CloudRunner extends runner("cloud") {
10754
10962
  #akanFrameworkPackages = new Set([
10755
10963
  "akanjs",
@@ -10774,21 +10982,138 @@ class CloudRunner extends runner("cloud") {
10774
10982
  NPM_CONFIG_REGISTRY: getNpmRegistryUrl(registryUrl)
10775
10983
  } : process.env;
10776
10984
  }
10985
+ async#addRemoteEnvServer() {
10986
+ const name = (await input5({
10987
+ message: "Remote server name: ",
10988
+ validate: (value) => value.trim() ? true : "Remote server name is required"
10989
+ })).trim();
10990
+ const host = (await input5({
10991
+ message: "Remote server host: ",
10992
+ validate: (value) => value.trim() ? true : "Remote server host is required"
10993
+ })).trim();
10994
+ const username = (await input5({ message: "Remote server username (optional): " })).trim() || undefined;
10995
+ const portInput = (await input5({
10996
+ message: "Remote server SSH port (optional): ",
10997
+ validate: (value) => {
10998
+ const trimmed = value.trim();
10999
+ if (!trimmed)
11000
+ return true;
11001
+ const port = Number(trimmed);
11002
+ return Number.isInteger(port) && port > 0 ? true : "SSH port must be a positive integer";
11003
+ }
11004
+ })).trim();
11005
+ const config = {
11006
+ host,
11007
+ ...username ? { username } : {},
11008
+ ...portInput ? { port: Number(portInput) } : {}
11009
+ };
11010
+ await GlobalConfig.setRemoteEnvServer(name, config);
11011
+ return { name, config };
11012
+ }
11013
+ async#selectRemoteEnvServer() {
11014
+ const servers = await GlobalConfig.getRemoteEnvServers();
11015
+ const serverEntries = Object.entries(servers).sort(([nameA], [nameB]) => nameA.localeCompare(nameB));
11016
+ if (serverEntries.length === 0) {
11017
+ Logger14.info("No remote env servers configured. Add the first remote server for SCP mode.");
11018
+ return await this.#addRemoteEnvServer();
11019
+ }
11020
+ const selectedName = await select7({
11021
+ message: "Select the remote env server",
11022
+ choices: [
11023
+ ...serverEntries.map(([name, config2]) => ({
11024
+ name: `${name} (${config2.username ? `${config2.username}@` : ""}${config2.host}${config2.port ? `:${config2.port}` : ""})`,
11025
+ value: name
11026
+ })),
11027
+ { name: "Add new remote server", value: addRemoteEnvServerValue },
11028
+ { name: "Remove remote server", value: removeRemoteEnvServerValue }
11029
+ ]
11030
+ });
11031
+ if (selectedName === addRemoteEnvServerValue)
11032
+ return await this.#addRemoteEnvServer();
11033
+ if (selectedName === removeRemoteEnvServerValue) {
11034
+ await this.#removeRemoteEnvServer(serverEntries);
11035
+ return await this.#selectRemoteEnvServer();
11036
+ }
11037
+ const config = servers[selectedName];
11038
+ if (!config)
11039
+ throw new Error(`Remote env server is not found: ${selectedName}`);
11040
+ return { name: selectedName, config };
11041
+ }
11042
+ async#removeRemoteEnvServer(serverEntries) {
11043
+ const selectedName = await select7({
11044
+ message: "Select the remote env server to remove",
11045
+ choices: serverEntries.map(([name, config]) => ({
11046
+ name: `${name} (${config.username ? `${config.username}@` : ""}${config.host}${config.port ? `:${config.port}` : ""})`,
11047
+ value: name
11048
+ }))
11049
+ });
11050
+ const shouldRemove = await confirm3({
11051
+ message: `Remove remote env server "${selectedName}"?`,
11052
+ default: false
11053
+ });
11054
+ if (!shouldRemove)
11055
+ return;
11056
+ await GlobalConfig.removeRemoteEnvServer(selectedName);
11057
+ Logger14.info(`Removed remote env server "${selectedName}"`);
11058
+ }
11059
+ async#getRemoteEnvServerWithUsername() {
11060
+ const remoteServer = await this.#selectRemoteEnvServer();
11061
+ if (remoteServer.config.username)
11062
+ return remoteServer;
11063
+ const username = (await input5({
11064
+ message: `SSH username for ${remoteServer.config.host} (optional): `
11065
+ })).trim();
11066
+ return {
11067
+ ...remoteServer,
11068
+ config: {
11069
+ ...remoteServer.config,
11070
+ ...username ? { username } : {}
11071
+ }
11072
+ };
11073
+ }
11074
+ #getRemoteEnvArchivePath() {
11075
+ return `${this.#getRemoteEnvArchiveDir()}/env.tar`;
11076
+ }
11077
+ #getRemoteEnvArchiveDir() {
11078
+ const { repoName } = WorkspaceExecutor.getBaseDevEnv();
11079
+ return `~/secrets/${repoName}`;
11080
+ }
11081
+ #getScpTarget(config, remotePath) {
11082
+ return `${config.username ? `${config.username}@` : ""}${config.host}:${remotePath}`;
11083
+ }
11084
+ #getSshTarget(config) {
11085
+ return `${config.username ? `${config.username}@` : ""}${config.host}`;
11086
+ }
11087
+ #getScpArgs(config, source, target) {
11088
+ return [
11089
+ ...config.port ? ["-P", config.port.toString()] : [],
11090
+ source,
11091
+ target
11092
+ ];
11093
+ }
11094
+ #getSshArgs(config, command3) {
11095
+ return [
11096
+ ...config.port ? ["-p", config.port.toString()] : [],
11097
+ this.#getSshTarget(config),
11098
+ command3
11099
+ ];
11100
+ }
10777
11101
  async login() {
10778
- const config = await getHostConfig();
10779
- const self2 = config.auth ? await getSelf(config.auth.token) : null;
10780
- if (self2) {
10781
- Logger15.rawLog(chalk7.green(`
10782
- \u2713 Already logged in akan cloud as ${self2.nickname}
11102
+ const config = await GlobalConfig.getHostConfig();
11103
+ const cloudApi2 = new CloudApi(config);
11104
+ const self = config.auth ? await cloudApi2.getRemoteSelf() : null;
11105
+ if (self) {
11106
+ Logger14.rawLog(chalk7.green(`
11107
+ \u2713 Already logged in akan cloud as ${self.nickname}
10783
11108
  `));
10784
11109
  return true;
10785
11110
  }
10786
11111
  const remoteId = crypto.randomUUID();
10787
11112
  const signinUrl = `${akanCloudUrl}/signin?remoteId=${remoteId}`;
10788
- Logger15.rawLog(chalk7.bold(`
11113
+ Logger14.rawLog(chalk7.bold(`
10789
11114
  ${chalk7.green("\u27A4")} Authentication Required`));
10790
- Logger15.rawLog(chalk7.dim("Please visit or click the following URL:"));
10791
- Logger15.rawLog(`${chalk7.cyan.underline(signinUrl)}
11115
+ Logger14.rawLog(chalk7.dim("Please visit or click the following URL:"));
11116
+ Logger14.rawLog(`${chalk7.cyan.underline(signinUrl)}
10792
11117
  `);
10793
11118
  try {
10794
11119
  const qrcode = await new Promise((resolve, reject) => {
@@ -10798,24 +11123,25 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10798
11123
  resolve(data);
10799
11124
  });
10800
11125
  });
10801
- Logger15.rawLog(qrcode);
11126
+ Logger14.rawLog(qrcode);
10802
11127
  await openBrowser(signinUrl);
10803
- Logger15.rawLog(chalk7.dim("Opening browser..."));
11128
+ Logger14.rawLog(chalk7.dim("Opening browser..."));
10804
11129
  } catch {
10805
- Logger15.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
11130
+ Logger14.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
10806
11131
  }
10807
- Logger15.rawLog(chalk7.dim("Waiting for authentication..."));
11132
+ Logger14.rawLog(chalk7.dim("Waiting for authentication..."));
10808
11133
  const MAX_RETRY = 300;
10809
11134
  for (let i = 0;i < MAX_RETRY; i++) {
10810
- const res = await fetch(`${akanCloudUrl}/user/getRemoteAuthToken/${remoteId}`);
10811
- const { jwt } = await res.json();
10812
- const self3 = jwt ? await getSelf(jwt) : null;
10813
- if (jwt && self3) {
10814
- setHostConfig(akanCloudHost, { auth: { token: jwt, self: self3 } });
10815
- Logger15.rawLog(chalk7.green(`\r\u2713 Authentication successful!`));
10816
- Logger15.rawLog(chalk7.green.bold(`
10817
- \u2728 Welcome aboard, ${self3.nickname}!`));
10818
- Logger15.rawLog(chalk7.dim(`You're now ready to use Akan CLI!
11135
+ const accessToken = await cloudApi2.getRemoteAuthToken(remoteId);
11136
+ const self2 = await cloudApi2.getRemoteSelf();
11137
+ if (accessToken && self2) {
11138
+ await GlobalConfig.setHostConfig(akanCloudHost, {
11139
+ auth: { accessToken, self: self2 }
11140
+ });
11141
+ Logger14.rawLog(chalk7.green(`\r\u2713 Authentication successful!`));
11142
+ Logger14.rawLog(chalk7.green.bold(`
11143
+ \u2728 Welcome aboard, ${self2.nickname}!`));
11144
+ Logger14.rawLog(chalk7.dim(`You're now ready to use Akan CLI!
10819
11145
  `));
10820
11146
  return true;
10821
11147
  }
@@ -10824,20 +11150,20 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10824
11150
  throw new Error(chalk7.red("\u2716 Authentication timed out after 10 minutes. Please try again."));
10825
11151
  }
10826
11152
  async logout() {
10827
- const config = await getHostConfig();
10828
- if (config.auth) {
10829
- setHostConfig(akanCloudHost, {});
10830
- Logger15.rawLog(chalk7.magenta.bold(`
11153
+ const config = await GlobalConfig.getHostConfig();
11154
+ if (config.auth?.self) {
11155
+ await GlobalConfig.setHostConfig(akanCloudHost, {});
11156
+ Logger14.rawLog(chalk7.magenta.bold(`
10831
11157
  \uD83D\uDC4B Goodbye, ${config.auth.self.nickname}!`));
10832
- Logger15.rawLog(chalk7.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
11158
+ Logger14.rawLog(chalk7.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
10833
11159
  `));
10834
- Logger15.rawLog(chalk7.cyan("You have been successfully logged out."));
10835
- Logger15.rawLog(chalk7.dim(`Thank you for using Akan CLI. Come back soon! \uD83C\uDF1F
11160
+ Logger14.rawLog(chalk7.cyan("You have been successfully logged out."));
11161
+ Logger14.rawLog(chalk7.dim(`Thank you for using Akan CLI. Come back soon! \uD83C\uDF1F
10836
11162
  `));
10837
11163
  } else {
10838
- Logger15.rawLog(chalk7.yellow.bold(`
11164
+ Logger14.rawLog(chalk7.yellow.bold(`
10839
11165
  \u26A0\uFE0F No active session found`));
10840
- Logger15.rawLog(chalk7.dim(`You were not logged in to begin with
11166
+ Logger14.rawLog(chalk7.dim(`You were not logged in to begin with
10841
11167
  `));
10842
11168
  }
10843
11169
  }
@@ -10846,7 +11172,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10846
11172
  }
10847
11173
  resetLlm() {
10848
11174
  AiSession.setLlmConfig(null);
10849
- Logger15.rawLog(chalk7.green("\u2611\uFE0F LLM model config is cleared. Please run `akan set-llm` to set a new LLM model."));
11175
+ Logger14.rawLog(chalk7.green("\u2611\uFE0F LLM model config is cleared. Please run `akan set-llm` to set a new LLM model."));
10850
11176
  }
10851
11177
  async getAkanPkgs(workspace) {
10852
11178
  const pkgs = await workspace.getPkgs();
@@ -10870,8 +11196,8 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10870
11196
  }
10871
11197
  };
10872
11198
  const { nextVersion, latestPublishedVersion } = await getNextVersion(targetVersionPrefix, tag);
10873
- Logger15.info(`Latest published version of akanjs: ${latestPublishedVersion ?? "none"}`);
10874
- Logger15.info(`Next version of akanjs: ${nextVersion}`);
11199
+ Logger14.info(`Latest published version of akanjs: ${latestPublishedVersion ?? "none"}`);
11200
+ Logger14.info(`Next version of akanjs: ${nextVersion}`);
10875
11201
  for (const library of akanPkgs) {
10876
11202
  const packageJson = await workspace.readJson(`pkgs/${library}/package.json`);
10877
11203
  const newPackageJsonStr = JSON.stringify(this.#normalizeAkanPackageJson(packageJson, library, nextVersion), null, 2);
@@ -10885,12 +11211,12 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10885
11211
  message: "Are you sure you want to deploy the libraries?"
10886
11212
  });
10887
11213
  if (!isDeployConfirmed) {
10888
- Logger15.error("Deployment cancelled");
11214
+ Logger14.error("Deployment cancelled");
10889
11215
  return;
10890
11216
  }
10891
11217
  }
10892
11218
  await Promise.all(akanPkgs.map(async (library) => {
10893
- Logger15.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
11219
+ Logger14.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
10894
11220
  await workspace.spawn("npm", [
10895
11221
  "publish",
10896
11222
  "--tag",
@@ -10902,9 +11228,9 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10902
11228
  env: this.#getRegistryEnv(registry),
10903
11229
  stdio: "inherit"
10904
11230
  });
10905
- Logger15.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
11231
+ Logger14.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
10906
11232
  }));
10907
- Logger15.info(`All libraries are published to ${registry ?? "npm"}`);
11233
+ Logger14.info(`All libraries are published to ${registry ?? "npm"}`);
10908
11234
  }
10909
11235
  async update(workspace, tag = "latest", { registryUrl } = {}) {
10910
11236
  const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
@@ -10961,20 +11287,78 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10961
11287
  }
10962
11288
  return normalized;
10963
11289
  }
10964
- async downloadEnv(workspace) {
10965
- const repoName = workspace.repoName;
10966
- const config = await getHostConfig();
10967
- const self2 = config.auth ? await getSelf(config.auth.token) : null;
10968
- if (!self2)
10969
- throw new Error("Not logged in");
10970
- const res = await fetch(`${akanCloudUrl}/api/akasys/akasys/${repoName}`, {
10971
- headers: { Authorization: `Bearer ${config.auth?.token}` }
11290
+ async downloadEnv(cloudApi2, workspace, workspaceId) {
11291
+ const envArchivePath = "local/env.tar";
11292
+ await workspace.mkdir("local");
11293
+ await workspace.remove(envArchivePath);
11294
+ await cloudApi2.downloadEnv(workspaceId, path38.join(workspace.workspaceRoot, envArchivePath));
11295
+ await workspace.spawn("tar", ["-xf", envArchivePath], {
11296
+ cwd: workspace.workspaceRoot
11297
+ });
11298
+ await workspace.remove(envArchivePath);
11299
+ }
11300
+ async uploadEnv(cloudApi2, workspaceId, filePath) {
11301
+ const file = new File([Bun.file(filePath)], path38.basename(filePath));
11302
+ await cloudApi2.uploadEnv(workspaceId, file);
11303
+ }
11304
+ async downloadEnvByScp(workspace) {
11305
+ const envArchivePath = "local/env.tar";
11306
+ const remoteServer = await this.#getRemoteEnvServerWithUsername();
11307
+ const remoteArchivePath = this.#getRemoteEnvArchivePath();
11308
+ const remoteTarget = this.#getScpTarget(remoteServer.config, remoteArchivePath);
11309
+ await workspace.mkdir("local");
11310
+ await workspace.remove(envArchivePath);
11311
+ try {
11312
+ Logger14.info(`Downloading env archive from remote server "${remoteServer.name}"...`);
11313
+ await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, remoteTarget, envArchivePath), {
11314
+ cwd: workspace.workspaceRoot,
11315
+ stdio: "inherit"
11316
+ });
11317
+ await workspace.spawn("tar", ["-xf", envArchivePath], {
11318
+ cwd: workspace.workspaceRoot
11319
+ });
11320
+ await workspace.remove(envArchivePath);
11321
+ } catch (error) {
11322
+ throw new Error(`Failed to download env archive from remote server "${remoteServer.name}"`, { cause: error });
11323
+ }
11324
+ }
11325
+ async uploadEnvByScp(workspace, filePath) {
11326
+ const remoteServer = await this.#getRemoteEnvServerWithUsername();
11327
+ const remoteArchiveDir = this.#getRemoteEnvArchiveDir();
11328
+ const remoteArchivePath = this.#getRemoteEnvArchivePath();
11329
+ const remoteTarget = this.#getScpTarget(remoteServer.config, remoteArchivePath);
11330
+ try {
11331
+ await workspace.spawn("ssh", this.#getSshArgs(remoteServer.config, `mkdir -p ${remoteArchiveDir}`), {
11332
+ cwd: workspace.workspaceRoot,
11333
+ stdio: "inherit"
11334
+ });
11335
+ Logger14.info(`Uploading env archive to remote server "${remoteServer.name}"...`);
11336
+ await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, filePath, remoteTarget), {
11337
+ cwd: workspace.workspaceRoot,
11338
+ stdio: "inherit"
11339
+ });
11340
+ } catch (error) {
11341
+ throw new Error(`Failed to upload env archive to remote server "${remoteServer.name}"`, { cause: error });
11342
+ }
11343
+ }
11344
+ async gatherEnvFiles(workspace) {
11345
+ const envFilePattern = /^env\.(client|server)\.(?!(type|example)\.ts$).+\.ts$/;
11346
+ const [appNames, libNames] = await workspace.getExecs();
11347
+ const envDirs = [
11348
+ ...appNames.map((appName) => `apps/${appName}/env`),
11349
+ ...libNames.map((libName) => `libs/${libName}/env`)
11350
+ ];
11351
+ const envFilePaths = (await Promise.all(envDirs.map(async (envDir) => (await workspace.readdir(envDir)).filter((fileName) => envFilePattern.test(fileName)).map((fileName) => `${envDir}/${fileName}`)))).flat().sort();
11352
+ await workspace.mkdir("local");
11353
+ await workspace.remove("local/env.tar");
11354
+ if (envFilePaths.length === 0)
11355
+ throw new Error("No environment files found to archive");
11356
+ await workspace.spawn("tar", ["-cf", "local/env.tar", ...envFilePaths], {
11357
+ cwd: workspace.workspaceRoot
10972
11358
  });
10973
- const env = await res.json();
10974
- Logger15.info(`Downloading environment variables from cloud...`);
10975
- Logger15.info(`Environment variables: ${JSON.stringify(env.env, null, 2)}`);
11359
+ Logger14.info(`Archived ${envFilePaths.length} environment files to local/env.tar`);
11360
+ return { files: envFilePaths, path: "local/env.tar" };
10976
11361
  }
10977
- async uploadEnv(workspace) {}
10978
11362
  }
10979
11363
 
10980
11364
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
@@ -11000,10 +11384,23 @@ class CloudScript extends script("cloud", [
11000
11384
  await session.ask(question);
11001
11385
  }
11002
11386
  async downloadEnv(workspace) {
11003
- await this.cloudRunner.downloadEnv(workspace);
11387
+ const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
11388
+ if (workspaceId) {
11389
+ const cloudApi2 = await CloudApi.fromHost();
11390
+ await this.cloudRunner.downloadEnv(cloudApi2, workspace, workspaceId);
11391
+ return;
11392
+ }
11393
+ await this.cloudRunner.downloadEnvByScp(workspace);
11004
11394
  }
11005
11395
  async uploadEnv(workspace) {
11006
- await this.cloudRunner.uploadEnv(workspace);
11396
+ const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
11397
+ const { path: path39 } = await this.cloudRunner.gatherEnvFiles(workspace);
11398
+ if (workspaceId) {
11399
+ const cloudApi2 = await CloudApi.fromHost();
11400
+ await this.cloudRunner.uploadEnv(cloudApi2, workspaceId, path39);
11401
+ return;
11402
+ }
11403
+ await this.cloudRunner.uploadEnvByScp(workspace, path39);
11007
11404
  }
11008
11405
  async deployAkan(workspace, { test = true, registryUrl } = {}) {
11009
11406
  const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
@@ -11020,7 +11417,7 @@ class CloudScript extends script("cloud", [
11020
11417
  const spinner2 = workspace.spinning("Updating Akan.js packages and CLI...");
11021
11418
  await this.cloudRunner.update(workspace, tag, { registryUrl });
11022
11419
  spinner2.succeed("Akan.js packages and CLI updated, global version is below");
11023
- Logger16.raw("> Akan version: ");
11420
+ Logger15.raw("> Akan version: ");
11024
11421
  await workspace.spawn("akan", ["--version"], { stdio: "inherit" });
11025
11422
  }
11026
11423
  }
@@ -11042,7 +11439,10 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
11042
11439
  resetLlm: target({ desc: "Reset LLM configuration to default" }).with(Workspace).exec(function(workspace) {
11043
11440
  this.cloudScript.resetLlm(workspace);
11044
11441
  }),
11045
- ask: target({ desc: "Ask AI assistant a question about your project" }).option("question", String, { ask: "question to ask" }).with(Workspace).exec(async function(question, workspace) {
11442
+ ask: target({
11443
+ devOnly: true,
11444
+ desc: "Ask AI assistant a question about your project"
11445
+ }).option("question", String, { ask: "question to ask" }).with(Workspace).exec(async function(question, workspace) {
11046
11446
  await this.cloudScript.ask(question, workspace);
11047
11447
  }),
11048
11448
  deployAkan: target({
@@ -11077,10 +11477,14 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
11077
11477
  registryUrl: resolveRegistryUrl(registry)
11078
11478
  });
11079
11479
  }),
11080
- downloadEnv: target({ desc: "Download environment variables from cloud" }).with(Workspace).exec(async function(workspace) {
11480
+ downloadEnv: target({
11481
+ desc: "Download environment variables from cloud or SCP server"
11482
+ }).with(Workspace).exec(async function(workspace) {
11081
11483
  await this.cloudScript.downloadEnv(workspace);
11082
11484
  }),
11083
- uploadEnv: target({ desc: "Upload environment variables to cloud" }).with(Workspace).exec(async function(workspace) {
11485
+ uploadEnv: target({
11486
+ desc: "Upload environment variables to cloud or SCP server"
11487
+ }).with(Workspace).exec(async function(workspace) {
11084
11488
  await this.cloudScript.uploadEnv(workspace);
11085
11489
  })
11086
11490
  })) {
@@ -11412,7 +11816,7 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
11412
11816
  // pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
11413
11817
  import { mkdir as mkdir11, rm as rm5 } from "fs/promises";
11414
11818
  import path39 from "path";
11415
- import { Logger as Logger17 } from "akanjs/common";
11819
+ import { Logger as Logger16 } from "akanjs/common";
11416
11820
  var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
11417
11821
  var containerName = "akan-verdaccio";
11418
11822
  var smokeRepoName = "akan-local-smoke";
@@ -11426,7 +11830,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
11426
11830
  const registry = this.getRegistryUrl(registryUrl);
11427
11831
  try {
11428
11832
  await workspace.spawn("docker", ["inspect", containerName]);
11429
- Logger17.info(`Local registry is already running at ${registry}`);
11833
+ Logger16.info(`Local registry is already running at ${registry}`);
11430
11834
  return registry;
11431
11835
  } catch {}
11432
11836
  const configPath2 = path39.join(workspace.workspaceRoot, "pkgs/@akanjs/cli/localRegistry/verdaccio.yaml");
@@ -11446,7 +11850,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
11446
11850
  `${storagePath}:/verdaccio/storage`,
11447
11851
  "verdaccio/verdaccio:6"
11448
11852
  ], { stdio: "inherit" });
11449
- Logger17.info(`Local registry is running at ${registry}`);
11853
+ Logger16.info(`Local registry is running at ${registry}`);
11450
11854
  return registry;
11451
11855
  }
11452
11856
  async reset(workspace) {
@@ -11454,7 +11858,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
11454
11858
  await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
11455
11859
  } catch {}
11456
11860
  await rm5(path39.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
11457
- Logger17.info("Local registry storage has been reset");
11861
+ Logger16.info("Local registry storage has been reset");
11458
11862
  }
11459
11863
  async smoke(workspace, { registryUrl } = {}) {
11460
11864
  const registry = this.getRegistryUrl(registryUrl);
@@ -11480,7 +11884,7 @@ class LocalRegistryRunner extends runner("localRegistry") {
11480
11884
  env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
11481
11885
  stdio: "inherit"
11482
11886
  });
11483
- Logger17.info(`Local registry smoke test completed for ${smokeRepoName}/${smokeAppName}`);
11887
+ Logger16.info(`Local registry smoke test completed for ${smokeRepoName}/${smokeAppName}`);
11484
11888
  }
11485
11889
  }
11486
11890
 
@@ -11554,7 +11958,7 @@ class LocalRegistryCommand extends command("local-registry", [LocalRegistryScrip
11554
11958
  import { lowerlize } from "akanjs/common";
11555
11959
 
11556
11960
  // pkgs/@akanjs/cli/module/module.script.ts
11557
- import { input as input5 } from "@inquirer/prompts";
11961
+ import { input as input6 } from "@inquirer/prompts";
11558
11962
  import { capitalize as capitalize6, randomPicks as randomPicks2 } from "akanjs/common";
11559
11963
 
11560
11964
  // pkgs/@akanjs/cli/page/page.runner.ts
@@ -11981,8 +12385,8 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
11981
12385
  const { constant, dictionary } = await this.moduleRunner.createModuleTemplate(executor);
11982
12386
  if (page && sys3.type === "app")
11983
12387
  await this.pageScript.createCrudPage(executor, { app: sys3, basePath: null, single: false });
11984
- const modelDesc = description ?? await input5({ message: "description of module" });
11985
- const modelSchemaDesign = schemaDescription ?? await input5({ message: "schema description of module" });
12388
+ const modelDesc = description ?? await input6({ message: "description of module" });
12389
+ const modelSchemaDesign = schemaDescription ?? await input6({ message: "schema description of module" });
11986
12390
  const config = await sys3.getConfig();
11987
12391
  const moduleRequest = new ModuleRequest({ sysType: sys3.type, sysName: sys3.name, modelName: name, config });
11988
12392
  const constantRequestPrompt = await moduleRequest.requestModelConstant({
@@ -12153,7 +12557,7 @@ class PageCommand extends command("page", [PageScript], ({ public: target }) =>
12153
12557
  import { lowerlize as lowerlize2 } from "akanjs/common";
12154
12558
 
12155
12559
  // pkgs/@akanjs/cli/scalar/scalar.prompt.ts
12156
- import { input as input6 } from "@inquirer/prompts";
12560
+ import { input as input7 } from "@inquirer/prompts";
12157
12561
  class ScalarPrompt extends Prompter {
12158
12562
  sys;
12159
12563
  name;
@@ -12163,13 +12567,13 @@ class ScalarPrompt extends Prompter {
12163
12567
  this.name = name;
12164
12568
  }
12165
12569
  async requestUpdateConstant() {
12166
- const request = await input6({ message: `What do you want to change?` });
12570
+ const request = await input7({ message: `What do you want to change?` });
12167
12571
  return { request, validate: undefined };
12168
12572
  }
12169
12573
  async requestCreateConstant() {
12170
12574
  const constantFiles = await this.sys.getConstantFilesWithLibs();
12171
- const description = await input6({ message: "description of scalar" });
12172
- const schemaDescription = await input6({ message: "schema description of scalar" });
12575
+ const description = await input7({ message: "description of scalar" });
12576
+ const schemaDescription = await input7({ message: "schema description of scalar" });
12173
12577
  await this.sys.applyTemplate({
12174
12578
  basePath: "./lib/__scalar",
12175
12579
  template: "__scalar",
@@ -12346,7 +12750,7 @@ class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target
12346
12750
 
12347
12751
  // pkgs/@akanjs/cli/workspace/workspace.script.ts
12348
12752
  import path41 from "path";
12349
- import { Logger as Logger18 } from "akanjs/common";
12753
+ import { Logger as Logger17 } from "akanjs/common";
12350
12754
 
12351
12755
  // pkgs/@akanjs/cli/workspace/workspace.runner.ts
12352
12756
  import path40 from "path";
@@ -12370,16 +12774,16 @@ var defaultWorkspacePeerDependencies = new Set([
12370
12774
 
12371
12775
  class WorkspaceRunner extends runner("workspace") {
12372
12776
  async createWorkspace(repoName, appName, {
12373
- dirname: dirname3 = ".",
12777
+ dirname: dirname2 = ".",
12374
12778
  init = true,
12375
12779
  akanVersion,
12376
12780
  registryUrl
12377
12781
  }) {
12378
12782
  const cwdPath = process.cwd();
12379
- const workspaceRoot = path40.join(cwdPath, dirname3, repoName);
12783
+ const workspaceRoot = path40.join(cwdPath, dirname2, repoName);
12380
12784
  const normalizedRegistryUrl = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
12381
12785
  const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
12382
- const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname3}/${repoName}...`);
12786
+ const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname2}/${repoName}...`);
12383
12787
  const [latestBiomeVersion, latestTypesBunVersion] = await Promise.all([
12384
12788
  getLatestPackageVersion("@biomejs/biome", "latest", normalizedRegistryUrl),
12385
12789
  getLatestPackageVersion("@types/bun", "latest", normalizedRegistryUrl)
@@ -12392,7 +12796,7 @@ class WorkspaceRunner extends runner("workspace") {
12392
12796
  if (normalizedRegistryUrl)
12393
12797
  await workspace.writeFile(".npmrc", `registry=${normalizedRegistryUrl}/
12394
12798
  `);
12395
- templateSpinner.succeed(`Workspace files created in ${dirname3}/${repoName}`);
12799
+ templateSpinner.succeed(`Workspace files created in ${dirname2}/${repoName}`);
12396
12800
  const [rootPackageJson, peerDependencies] = await Promise.all([
12397
12801
  workspace.getPackageJson(),
12398
12802
  this.#getAkanPeerDependencies()
@@ -12497,14 +12901,14 @@ class WorkspaceScript extends script("workspace", [
12497
12901
  PackageScript
12498
12902
  ]) {
12499
12903
  async createWorkspace(repoName, appName, {
12500
- dirname: dirname3 = ".",
12904
+ dirname: dirname2 = ".",
12501
12905
  installLibs = false,
12502
12906
  init = true,
12503
12907
  registryUrl
12504
12908
  }) {
12505
12909
  const akanVersion = await this.packageScript.version(null, { log: false });
12506
12910
  const workspace = await this.workspaceRunner.createWorkspace(repoName, appName, {
12507
- dirname: dirname3,
12911
+ dirname: dirname2,
12508
12912
  init,
12509
12913
  akanVersion,
12510
12914
  ...registryUrl ? { registryUrl } : {}
@@ -12521,11 +12925,11 @@ class WorkspaceScript extends script("workspace", [
12521
12925
  } catch (_) {
12522
12926
  gitSpinner.fail("Git repository initialization failed. It's not fatal, you can commit manually");
12523
12927
  }
12524
- const workspacePath = path41.join(dirname3, repoName);
12525
- Logger18.rawLog(`
12526
- \uD83C\uDF89 Welcome aboard! Workspace created in ${dirname3}/${repoName}`);
12527
- Logger18.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
12528
- Logger18.rawLog(`
12928
+ const workspacePath = path41.join(dirname2, repoName);
12929
+ Logger17.rawLog(`
12930
+ \uD83C\uDF89 Welcome aboard! Workspace created in ${dirname2}/${repoName}`);
12931
+ Logger17.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
12932
+ Logger17.rawLog(`
12529
12933
  \uD83D\uDC4B Happy coding!`);
12530
12934
  }
12531
12935
  async lint(exec2, workspace, { fix = true } = {}) {