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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }
420
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
+ }
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,18 @@ 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
+ ];
484
330
 
485
331
  class AiSession {
486
332
  static #cacheDir = "node_modules/.cache/akan/aiSession";
487
333
  static #chat = null;
488
- static async init({ temperature = 0, useExisting = true } = {}) {
334
+ static async init({
335
+ temperature = 0,
336
+ useExisting = true
337
+ } = {}) {
489
338
  if (useExisting) {
490
339
  const llmConfig2 = await AiSession.getLlmConfig();
491
340
  if (llmConfig2) {
@@ -512,22 +361,24 @@ class AiSession {
512
361
  return AiSession;
513
362
  }
514
363
  static async getLlmConfig() {
515
- const akanConfig = await getAkanGlobalConfig();
516
- return akanConfig.llm ?? null;
364
+ return await GlobalConfig.getLlmConfig();
517
365
  }
518
366
  static async setLlmConfig(llmConfig) {
519
- const akanConfig = await getAkanGlobalConfig();
520
- akanConfig.llm = llmConfig;
521
- await setAkanGlobalConfig(akanConfig);
367
+ await GlobalConfig.setLlmConfig(llmConfig);
522
368
  return AiSession;
523
369
  }
524
370
  static async#requestLlmConfig() {
525
- const model = await select({ message: "Select a LLM model", choices: supportedLlmModels });
371
+ const model = await select({
372
+ message: "Select a LLM model",
373
+ choices: supportedLlmModels
374
+ });
526
375
  const apiKey = await input({ message: "Enter your API key" });
527
376
  return { model, apiKey };
528
377
  }
529
378
  static async#validateApiKey(modelName, apiKey) {
530
- const spinner = new Spinner("Validating LLM API key...", { prefix: `\uD83E\uDD16akan-editor` }).start();
379
+ const spinner = new Spinner("Validating LLM API key...", {
380
+ prefix: `\uD83E\uDD16akan-editor`
381
+ }).start();
531
382
  const chat = new ChatOpenAI({
532
383
  modelName,
533
384
  temperature: 0,
@@ -550,7 +401,11 @@ class AiSession {
550
401
  sessionKey;
551
402
  isCacheLoaded = false;
552
403
  workspace;
553
- constructor(type, { workspace, cacheKey, isContinued }) {
404
+ constructor(type, {
405
+ workspace,
406
+ cacheKey,
407
+ isContinued
408
+ }) {
554
409
  this.workspace = workspace;
555
410
  this.sessionKey = `${type}${cacheKey ? `-${cacheKey}` : ""}`;
556
411
  if (isContinued)
@@ -625,7 +480,13 @@ class AiSession {
625
480
  throw new Error("Failed to stream response");
626
481
  }
627
482
  }
628
- async edit(question, { onChunk, onReasoning, maxTry = MAX_ASK_TRY, validate, approve } = {}) {
483
+ async edit(question, {
484
+ onChunk,
485
+ onReasoning,
486
+ maxTry = MAX_ASK_TRY,
487
+ validate,
488
+ approve
489
+ } = {}) {
629
490
  for (let tryCount = 0;tryCount < maxTry; tryCount++) {
630
491
  let response = await this.ask(question, { onChunk, onReasoning });
631
492
  if (validate?.length && tryCount === 0) {
@@ -678,7 +539,9 @@ ${validate.map((v) => `- ${v}`).join(`
678
539
  async#tryFixTypescripts(writes, executor, options = {}) {
679
540
  const MAX_EDIT_TRY = 5;
680
541
  for (let tryCount = 0;tryCount < MAX_EDIT_TRY; tryCount++) {
681
- const loader = new Spinner(`Type checking and linting...`, { prefix: `\uD83E\uDD16akan-editor` }).start();
542
+ const loader = new Spinner(`Type checking and linting...`, {
543
+ prefix: `\uD83E\uDD16akan-editor`
544
+ }).start();
682
545
  const fileChecks = await Promise.all(writes.map(async ({ filePath }) => {
683
546
  const typeCheckResult = executor.typeCheck(filePath);
684
547
  const lintResult = await executor.lint(filePath);
@@ -2486,11 +2349,26 @@ class Executor {
2486
2349
  });
2487
2350
  return new Promise((resolve, reject) => {
2488
2351
  proc.on("error", (error) => {
2489
- reject(new CommandExecutionError({ command, cwd, code: null, signal: null, stdout, stderr, cause: error }));
2352
+ reject(new CommandExecutionError({
2353
+ command,
2354
+ cwd,
2355
+ code: null,
2356
+ signal: null,
2357
+ stdout,
2358
+ stderr,
2359
+ cause: error
2360
+ }));
2490
2361
  });
2491
2362
  proc.on("exit", (code, signal) => {
2492
2363
  if (!!code || signal)
2493
- reject(new CommandExecutionError({ command, cwd, code, signal, stdout, stderr }));
2364
+ reject(new CommandExecutionError({
2365
+ command,
2366
+ cwd,
2367
+ code,
2368
+ signal,
2369
+ stdout,
2370
+ stderr
2371
+ }));
2494
2372
  else
2495
2373
  resolve({ code, signal });
2496
2374
  });
@@ -2516,11 +2394,28 @@ class Executor {
2516
2394
  });
2517
2395
  return new Promise((resolve, reject) => {
2518
2396
  proc.on("error", (error) => {
2519
- reject(new CommandExecutionError({ command, args, cwd, code: null, signal: null, stdout, stderr, cause: error }));
2397
+ reject(new CommandExecutionError({
2398
+ command,
2399
+ args,
2400
+ cwd,
2401
+ code: null,
2402
+ signal: null,
2403
+ stdout,
2404
+ stderr,
2405
+ cause: error
2406
+ }));
2520
2407
  });
2521
2408
  proc.on("close", (code, signal) => {
2522
2409
  if (code !== 0 || signal)
2523
- reject(new CommandExecutionError({ command, args, cwd, code, signal, stdout, stderr }));
2410
+ reject(new CommandExecutionError({
2411
+ command,
2412
+ args,
2413
+ cwd,
2414
+ code,
2415
+ signal,
2416
+ stdout,
2417
+ stderr
2418
+ }));
2524
2419
  else
2525
2420
  resolve(stdout);
2526
2421
  });
@@ -2564,7 +2459,15 @@ class Executor {
2564
2459
  });
2565
2460
  proc.on("exit", (code, signal) => {
2566
2461
  if (!!code || signal)
2567
- reject(new CommandExecutionError({ command: modulePath, args, cwd, code, signal, stdout, stderr }));
2462
+ reject(new CommandExecutionError({
2463
+ command: modulePath,
2464
+ args,
2465
+ cwd,
2466
+ code,
2467
+ signal,
2468
+ stdout,
2469
+ stderr
2470
+ }));
2568
2471
  else
2569
2472
  resolve({ code, signal });
2570
2473
  });
@@ -2711,7 +2614,10 @@ class Executor {
2711
2614
  const result = {
2712
2615
  ...extendsTsconfig,
2713
2616
  ...tsconfig,
2714
- compilerOptions: { ...extendsTsconfig.compilerOptions, ...tsconfig.compilerOptions }
2617
+ compilerOptions: {
2618
+ ...extendsTsconfig.compilerOptions,
2619
+ ...tsconfig.compilerOptions
2620
+ }
2715
2621
  };
2716
2622
  this.#tsconfig = result;
2717
2623
  return result;
@@ -2766,7 +2672,9 @@ class Executor {
2766
2672
  const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath.slice(0, -9));
2767
2673
  const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
2768
2674
  this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
2769
- return this.writeFile(convertedTargetPath, convertedContent, { overwrite });
2675
+ return this.writeFile(convertedTargetPath, convertedContent, {
2676
+ overwrite
2677
+ });
2770
2678
  } else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
2771
2679
  const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
2772
2680
  const writePath = this.getPath(convertedTargetPath);
@@ -2792,14 +2700,24 @@ class Executor {
2792
2700
  const prefixTemplatePath = templatePath;
2793
2701
  if ((await stat2(prefixTemplatePath)).isFile()) {
2794
2702
  const filename = path7.basename(prefixTemplatePath);
2795
- const fileContent = await this.#applyTemplateFile({ templatePath: prefixTemplatePath, targetPath: path7.join(basePath2, filename), scanInfo, overwrite }, dict, options);
2703
+ const fileContent = await this.#applyTemplateFile({
2704
+ templatePath: prefixTemplatePath,
2705
+ targetPath: path7.join(basePath2, filename),
2706
+ scanInfo,
2707
+ overwrite
2708
+ }, dict, options);
2796
2709
  return fileContent ? [fileContent] : [];
2797
2710
  } else {
2798
2711
  const subdirs = await readDirEntries(templatePath);
2799
2712
  const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
2800
2713
  const subpath = path7.join(templatePath, subdir);
2801
2714
  if ((await stat2(subpath)).isFile()) {
2802
- const fileContent = await this.#applyTemplateFile({ templatePath: subpath, targetPath: path7.join(basePath2, subdir), scanInfo, overwrite }, dict, options);
2715
+ const fileContent = await this.#applyTemplateFile({
2716
+ templatePath: subpath,
2717
+ targetPath: path7.join(basePath2, subdir),
2718
+ scanInfo,
2719
+ overwrite
2720
+ }, dict, options);
2803
2721
  return fileContent ? [fileContent] : [];
2804
2722
  } else
2805
2723
  return await this._applyTemplate({
@@ -2850,7 +2768,10 @@ class Executor {
2850
2768
  async lint(filePath, { fix = false, dryRun = false } = {}) {
2851
2769
  const path8 = this.getPath(filePath);
2852
2770
  const linter = this.getLinter();
2853
- const { results, errors, warnings } = await linter.lint(path8, { fix, dryRun });
2771
+ const { results, errors, warnings } = await linter.lint(path8, {
2772
+ fix,
2773
+ dryRun
2774
+ });
2854
2775
  const message = linter.formatLintResults(results);
2855
2776
  return { results, message, errors, warnings };
2856
2777
  }
@@ -2876,6 +2797,7 @@ class WorkspaceExecutor extends Executor {
2876
2797
  const sourceEnv = envPath ? { ...process.env, ...parseEnvFile(envPath) } : process.env;
2877
2798
  const appName = sourceEnv.AKAN_PUBLIC_APP_NAME;
2878
2799
  const workspaceRoot = sourceEnv.AKAN_WORKSPACE_ROOT;
2800
+ const workspaceId = sourceEnv.AKAN_WORKSPACE_ID;
2879
2801
  const repoName = sourceEnv.AKAN_PUBLIC_REPO_NAME;
2880
2802
  if (!repoName)
2881
2803
  throw new Error("AKAN_PUBLIC_REPO_NAME is not set");
@@ -2886,7 +2808,15 @@ class WorkspaceExecutor extends Executor {
2886
2808
  const env = sourceEnv.AKAN_PUBLIC_ENV ?? "debug";
2887
2809
  if (!env)
2888
2810
  throw new Error("AKAN_PUBLIC_ENV is not set");
2889
- return { ...appName ? { appName } : {}, workspaceRoot, repoName, serveDomain, env, portOffset };
2811
+ return { ...appName ? { appName } : {}, workspaceRoot, repoName, serveDomain, env, portOffset, workspaceId };
2812
+ }
2813
+ getWorkspaceId({
2814
+ allowEmpty
2815
+ } = {}) {
2816
+ const { workspaceId } = WorkspaceExecutor.getBaseDevEnv();
2817
+ if (!workspaceId && !allowEmpty)
2818
+ throw new Error("Workspace ID is not found");
2819
+ return workspaceId;
2890
2820
  }
2891
2821
  async scan() {
2892
2822
  return await WorkspaceInfo.fromExecutor(this);
@@ -3090,7 +3020,11 @@ class SysExecutor extends Executor {
3090
3020
  } = {}) {
3091
3021
  if (this.#scanInfo && !refresh)
3092
3022
  return this.#scanInfo;
3093
- const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, { refresh }) : await LibInfo.fromExecutor(this, { refresh });
3023
+ const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, {
3024
+ refresh
3025
+ }) : await LibInfo.fromExecutor(this, {
3026
+ refresh
3027
+ });
3094
3028
  if (write) {
3095
3029
  await Promise.all(this.#getScanTemplateTasks(scanInfo));
3096
3030
  await this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
@@ -3199,7 +3133,11 @@ class SysExecutor extends Executor {
3199
3133
  ...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [capitalize(key), capitalize(value)]))
3200
3134
  };
3201
3135
  const scanInfo = await this.scan();
3202
- const fileContents = await this._applyTemplate({ ...options, scanInfo, dict });
3136
+ const fileContents = await this._applyTemplate({
3137
+ ...options,
3138
+ scanInfo,
3139
+ dict
3140
+ });
3203
3141
  await this.scan();
3204
3142
  return fileContents;
3205
3143
  }
@@ -3305,7 +3243,11 @@ class AppExecutor extends SysExecutor {
3305
3243
  this.#pageKeys = [];
3306
3244
  return this.#pageKeys;
3307
3245
  }
3308
- for await (const rel of glob.scan({ cwd: pageDir, absolute: false, onlyFiles: true })) {
3246
+ for await (const rel of glob.scan({
3247
+ cwd: pageDir,
3248
+ absolute: false,
3249
+ onlyFiles: true
3250
+ })) {
3309
3251
  const segments = rel.split(path7.sep);
3310
3252
  if (segments.some((s) => s === "node_modules"))
3311
3253
  continue;
@@ -3315,7 +3257,10 @@ class AppExecutor extends SysExecutor {
3315
3257
  if (!isRouteSourceFile(posix))
3316
3258
  continue;
3317
3259
  const key = `./${posix}`;
3318
- validateSubRoutePageKey(key, akanConfig2.basePaths, { appName: this.name, filePath: absPath });
3260
+ validateSubRoutePageKey(key, akanConfig2.basePaths, {
3261
+ appName: this.name,
3262
+ filePath: absPath
3263
+ });
3319
3264
  const parsed = parseRouteModuleKey(key);
3320
3265
  if (parsed.isInternalRootLayout) {
3321
3266
  throw new Error(`[route-convention] __root_layout is reserved for Akan.js generated root layout: ${absPath}`);
@@ -3355,7 +3300,11 @@ class AppExecutor extends SysExecutor {
3355
3300
  ]);
3356
3301
  }
3357
3302
  async scanSync({ refresh = false, write = true } = {}) {
3358
- const scanInfo = await this.scan({ refresh, write, writeLib: write });
3303
+ const scanInfo = await this.scan({
3304
+ refresh,
3305
+ write,
3306
+ writeLib: write
3307
+ });
3359
3308
  if (write)
3360
3309
  await this.syncAssets(scanInfo.getScanResult().libDeps);
3361
3310
  return scanInfo;
@@ -3419,7 +3368,10 @@ class PkgExecutor extends Executor {
3419
3368
  return scanInfo;
3420
3369
  }
3421
3370
  async#getDependencyVersion(rootPackageJson, dep) {
3422
- const rootDeps = { ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies };
3371
+ const rootDeps = {
3372
+ ...rootPackageJson.dependencies,
3373
+ ...rootPackageJson.devDependencies
3374
+ };
3423
3375
  const rootVersion = rootDeps[dep];
3424
3376
  if (rootVersion)
3425
3377
  return rootVersion;
@@ -3475,7 +3427,14 @@ class PkgExecutor extends Executor {
3475
3427
  const distPkgJson = {
3476
3428
  ...pkgJson,
3477
3429
  type: "module",
3478
- exports: { ...pkgJson.exports, ".": { import: "./index.ts", types: "./index.ts", default: "./index.ts" } },
3430
+ exports: {
3431
+ ...pkgJson.exports,
3432
+ ".": {
3433
+ import: "./index.ts",
3434
+ types: "./index.ts",
3435
+ default: "./index.ts"
3436
+ }
3437
+ },
3479
3438
  engines: { bun: ">=1.3.13" },
3480
3439
  ...dependencyMaps
3481
3440
  };
@@ -7769,7 +7728,7 @@ class ApplicationBuildRunner {
7769
7728
  import { cp, mkdir as mkdir8, rm as rm3 } from "fs/promises";
7770
7729
 
7771
7730
  // pkgs/@akanjs/devkit/uploadRelease.ts
7772
- import { HttpClient, Logger as Logger10 } from "akanjs/common";
7731
+ import { HttpClient as HttpClient2, Logger as Logger10 } from "akanjs/common";
7773
7732
  var spinning = (message) => {
7774
7733
  const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
7775
7734
  return spinner;
@@ -7784,7 +7743,7 @@ var uploadRelease = async (appName, {
7784
7743
  }) => {
7785
7744
  const logger = new Logger10("uploadRelease");
7786
7745
  const basePath2 = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
7787
- const httpClient = new HttpClient(basePath2);
7746
+ const httpClient = new HttpClient2(basePath2);
7788
7747
  const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
7789
7748
  const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
7790
7749
  const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
@@ -9771,77 +9730,6 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
9771
9730
  import { useEffect as useEffect3, useState as useState3 } from "react";
9772
9731
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9773
9732
  "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
9733
  // pkgs/@akanjs/cli/application/application.command.ts
9846
9734
  import { select as select6 } from "@inquirer/prompts";
9847
9735
 
@@ -10728,7 +10616,7 @@ class PackageScript extends script("package", [PackageRunner]) {
10728
10616
 
10729
10617
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
10730
10618
  import path38 from "path";
10731
- import { confirm as confirm3 } from "@inquirer/prompts";
10619
+ import { confirm as confirm3, input as input5, select as select7 } from "@inquirer/prompts";
10732
10620
  import { Logger as Logger15, sleep } from "akanjs/common";
10733
10621
  import chalk7 from "chalk";
10734
10622
  import * as QRcode from "qrcode";
@@ -10750,6 +10638,9 @@ async function getLatestPackageVersion(packageName, tag = "latest", registryUrl)
10750
10638
  }
10751
10639
 
10752
10640
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
10641
+ var addRemoteEnvServerValue = "__addRemoteEnvServer";
10642
+ var removeRemoteEnvServerValue = "__removeRemoteEnvServer";
10643
+
10753
10644
  class CloudRunner extends runner("cloud") {
10754
10645
  #akanFrameworkPackages = new Set([
10755
10646
  "akanjs",
@@ -10774,12 +10665,129 @@ class CloudRunner extends runner("cloud") {
10774
10665
  NPM_CONFIG_REGISTRY: getNpmRegistryUrl(registryUrl)
10775
10666
  } : process.env;
10776
10667
  }
10668
+ async#addRemoteEnvServer() {
10669
+ const name = (await input5({
10670
+ message: "Remote server name: ",
10671
+ validate: (value) => value.trim() ? true : "Remote server name is required"
10672
+ })).trim();
10673
+ const host = (await input5({
10674
+ message: "Remote server host: ",
10675
+ validate: (value) => value.trim() ? true : "Remote server host is required"
10676
+ })).trim();
10677
+ const username = (await input5({ message: "Remote server username (optional): " })).trim() || undefined;
10678
+ const portInput = (await input5({
10679
+ message: "Remote server SSH port (optional): ",
10680
+ validate: (value) => {
10681
+ const trimmed = value.trim();
10682
+ if (!trimmed)
10683
+ return true;
10684
+ const port = Number(trimmed);
10685
+ return Number.isInteger(port) && port > 0 ? true : "SSH port must be a positive integer";
10686
+ }
10687
+ })).trim();
10688
+ const config = {
10689
+ host,
10690
+ ...username ? { username } : {},
10691
+ ...portInput ? { port: Number(portInput) } : {}
10692
+ };
10693
+ await GlobalConfig.setRemoteEnvServer(name, config);
10694
+ return { name, config };
10695
+ }
10696
+ async#selectRemoteEnvServer() {
10697
+ const servers = await GlobalConfig.getRemoteEnvServers();
10698
+ const serverEntries = Object.entries(servers).sort(([nameA], [nameB]) => nameA.localeCompare(nameB));
10699
+ if (serverEntries.length === 0) {
10700
+ Logger15.info("No remote env servers configured. Add the first remote server for SCP mode.");
10701
+ return await this.#addRemoteEnvServer();
10702
+ }
10703
+ const selectedName = await select7({
10704
+ message: "Select the remote env server",
10705
+ choices: [
10706
+ ...serverEntries.map(([name, config2]) => ({
10707
+ name: `${name} (${config2.username ? `${config2.username}@` : ""}${config2.host}${config2.port ? `:${config2.port}` : ""})`,
10708
+ value: name
10709
+ })),
10710
+ { name: "Add new remote server", value: addRemoteEnvServerValue },
10711
+ { name: "Remove remote server", value: removeRemoteEnvServerValue }
10712
+ ]
10713
+ });
10714
+ if (selectedName === addRemoteEnvServerValue)
10715
+ return await this.#addRemoteEnvServer();
10716
+ if (selectedName === removeRemoteEnvServerValue) {
10717
+ await this.#removeRemoteEnvServer(serverEntries);
10718
+ return await this.#selectRemoteEnvServer();
10719
+ }
10720
+ const config = servers[selectedName];
10721
+ if (!config)
10722
+ throw new Error(`Remote env server is not found: ${selectedName}`);
10723
+ return { name: selectedName, config };
10724
+ }
10725
+ async#removeRemoteEnvServer(serverEntries) {
10726
+ const selectedName = await select7({
10727
+ message: "Select the remote env server to remove",
10728
+ choices: serverEntries.map(([name, config]) => ({
10729
+ name: `${name} (${config.username ? `${config.username}@` : ""}${config.host}${config.port ? `:${config.port}` : ""})`,
10730
+ value: name
10731
+ }))
10732
+ });
10733
+ const shouldRemove = await confirm3({
10734
+ message: `Remove remote env server "${selectedName}"?`,
10735
+ default: false
10736
+ });
10737
+ if (!shouldRemove)
10738
+ return;
10739
+ await GlobalConfig.removeRemoteEnvServer(selectedName);
10740
+ Logger15.info(`Removed remote env server "${selectedName}"`);
10741
+ }
10742
+ async#getRemoteEnvServerWithUsername() {
10743
+ const remoteServer = await this.#selectRemoteEnvServer();
10744
+ if (remoteServer.config.username)
10745
+ return remoteServer;
10746
+ const username = (await input5({
10747
+ message: `SSH username for ${remoteServer.config.host} (optional): `
10748
+ })).trim();
10749
+ return {
10750
+ ...remoteServer,
10751
+ config: {
10752
+ ...remoteServer.config,
10753
+ ...username ? { username } : {}
10754
+ }
10755
+ };
10756
+ }
10757
+ #getRemoteEnvArchivePath() {
10758
+ return `${this.#getRemoteEnvArchiveDir()}/env.tar`;
10759
+ }
10760
+ #getRemoteEnvArchiveDir() {
10761
+ const { repoName } = WorkspaceExecutor.getBaseDevEnv();
10762
+ return `~/secrets/${repoName}`;
10763
+ }
10764
+ #getScpTarget(config, remotePath) {
10765
+ return `${config.username ? `${config.username}@` : ""}${config.host}:${remotePath}`;
10766
+ }
10767
+ #getSshTarget(config) {
10768
+ return `${config.username ? `${config.username}@` : ""}${config.host}`;
10769
+ }
10770
+ #getScpArgs(config, source, target) {
10771
+ return [
10772
+ ...config.port ? ["-P", config.port.toString()] : [],
10773
+ source,
10774
+ target
10775
+ ];
10776
+ }
10777
+ #getSshArgs(config, command3) {
10778
+ return [
10779
+ ...config.port ? ["-p", config.port.toString()] : [],
10780
+ this.#getSshTarget(config),
10781
+ command3
10782
+ ];
10783
+ }
10777
10784
  async login() {
10778
- const config = await getHostConfig();
10779
- const self2 = config.auth ? await getSelf(config.auth.token) : null;
10780
- if (self2) {
10785
+ const config = await GlobalConfig.getHostConfig();
10786
+ const cloudApi2 = new CloudApi(config);
10787
+ const self = config.auth ? await cloudApi2.getRemoteSelf() : null;
10788
+ if (self) {
10781
10789
  Logger15.rawLog(chalk7.green(`
10782
- \u2713 Already logged in akan cloud as ${self2.nickname}
10790
+ \u2713 Already logged in akan cloud as ${self.nickname}
10783
10791
  `));
10784
10792
  return true;
10785
10793
  }
@@ -10807,14 +10815,15 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10807
10815
  Logger15.rawLog(chalk7.dim("Waiting for authentication..."));
10808
10816
  const MAX_RETRY = 300;
10809
10817
  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 } });
10818
+ const accessToken = await cloudApi2.getRemoteAuthToken(remoteId);
10819
+ const self2 = await cloudApi2.getRemoteSelf();
10820
+ if (accessToken && self2) {
10821
+ await GlobalConfig.setHostConfig(akanCloudHost, {
10822
+ auth: { accessToken, self: self2 }
10823
+ });
10815
10824
  Logger15.rawLog(chalk7.green(`\r\u2713 Authentication successful!`));
10816
10825
  Logger15.rawLog(chalk7.green.bold(`
10817
- \u2728 Welcome aboard, ${self3.nickname}!`));
10826
+ \u2728 Welcome aboard, ${self2.nickname}!`));
10818
10827
  Logger15.rawLog(chalk7.dim(`You're now ready to use Akan CLI!
10819
10828
  `));
10820
10829
  return true;
@@ -10824,9 +10833,9 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10824
10833
  throw new Error(chalk7.red("\u2716 Authentication timed out after 10 minutes. Please try again."));
10825
10834
  }
10826
10835
  async logout() {
10827
- const config = await getHostConfig();
10828
- if (config.auth) {
10829
- setHostConfig(akanCloudHost, {});
10836
+ const config = await GlobalConfig.getHostConfig();
10837
+ if (config.auth?.self) {
10838
+ await GlobalConfig.setHostConfig(akanCloudHost, {});
10830
10839
  Logger15.rawLog(chalk7.magenta.bold(`
10831
10840
  \uD83D\uDC4B Goodbye, ${config.auth.self.nickname}!`));
10832
10841
  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
@@ -10961,20 +10970,78 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10961
10970
  }
10962
10971
  return normalized;
10963
10972
  }
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}` }
10973
+ async downloadEnv(cloudApi2, workspace, workspaceId) {
10974
+ const envArchivePath = "local/env.tar";
10975
+ await workspace.mkdir("local");
10976
+ await workspace.remove(envArchivePath);
10977
+ await cloudApi2.downloadEnv(workspaceId, path38.join(workspace.workspaceRoot, envArchivePath));
10978
+ await workspace.spawn("tar", ["-xf", envArchivePath], {
10979
+ cwd: workspace.workspaceRoot
10980
+ });
10981
+ await workspace.remove(envArchivePath);
10982
+ }
10983
+ async uploadEnv(cloudApi2, workspaceId, filePath) {
10984
+ const file = new File([Bun.file(filePath)], path38.basename(filePath));
10985
+ await cloudApi2.uploadEnv(workspaceId, file);
10986
+ }
10987
+ async downloadEnvByScp(workspace) {
10988
+ const envArchivePath = "local/env.tar";
10989
+ const remoteServer = await this.#getRemoteEnvServerWithUsername();
10990
+ const remoteArchivePath = this.#getRemoteEnvArchivePath();
10991
+ const remoteTarget = this.#getScpTarget(remoteServer.config, remoteArchivePath);
10992
+ await workspace.mkdir("local");
10993
+ await workspace.remove(envArchivePath);
10994
+ try {
10995
+ Logger15.info(`Downloading env archive from remote server "${remoteServer.name}"...`);
10996
+ await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, remoteTarget, envArchivePath), {
10997
+ cwd: workspace.workspaceRoot,
10998
+ stdio: "inherit"
10999
+ });
11000
+ await workspace.spawn("tar", ["-xf", envArchivePath], {
11001
+ cwd: workspace.workspaceRoot
11002
+ });
11003
+ await workspace.remove(envArchivePath);
11004
+ } catch (error) {
11005
+ throw new Error(`Failed to download env archive from remote server "${remoteServer.name}"`, { cause: error });
11006
+ }
11007
+ }
11008
+ async uploadEnvByScp(workspace, filePath) {
11009
+ const remoteServer = await this.#getRemoteEnvServerWithUsername();
11010
+ const remoteArchiveDir = this.#getRemoteEnvArchiveDir();
11011
+ const remoteArchivePath = this.#getRemoteEnvArchivePath();
11012
+ const remoteTarget = this.#getScpTarget(remoteServer.config, remoteArchivePath);
11013
+ try {
11014
+ await workspace.spawn("ssh", this.#getSshArgs(remoteServer.config, `mkdir -p ${remoteArchiveDir}`), {
11015
+ cwd: workspace.workspaceRoot,
11016
+ stdio: "inherit"
11017
+ });
11018
+ Logger15.info(`Uploading env archive to remote server "${remoteServer.name}"...`);
11019
+ await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, filePath, remoteTarget), {
11020
+ cwd: workspace.workspaceRoot,
11021
+ stdio: "inherit"
11022
+ });
11023
+ } catch (error) {
11024
+ throw new Error(`Failed to upload env archive to remote server "${remoteServer.name}"`, { cause: error });
11025
+ }
11026
+ }
11027
+ async gatherEnvFiles(workspace) {
11028
+ const envFilePattern = /^env\.(client|server)\.(?!(type|example)\.ts$).+\.ts$/;
11029
+ const [appNames, libNames] = await workspace.getExecs();
11030
+ const envDirs = [
11031
+ ...appNames.map((appName) => `apps/${appName}/env`),
11032
+ ...libNames.map((libName) => `libs/${libName}/env`)
11033
+ ];
11034
+ const envFilePaths = (await Promise.all(envDirs.map(async (envDir) => (await workspace.readdir(envDir)).filter((fileName) => envFilePattern.test(fileName)).map((fileName) => `${envDir}/${fileName}`)))).flat().sort();
11035
+ await workspace.mkdir("local");
11036
+ await workspace.remove("local/env.tar");
11037
+ if (envFilePaths.length === 0)
11038
+ throw new Error("No environment files found to archive");
11039
+ await workspace.spawn("tar", ["-cf", "local/env.tar", ...envFilePaths], {
11040
+ cwd: workspace.workspaceRoot
10972
11041
  });
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)}`);
11042
+ Logger15.info(`Archived ${envFilePaths.length} environment files to local/env.tar`);
11043
+ return { files: envFilePaths, path: "local/env.tar" };
10976
11044
  }
10977
- async uploadEnv(workspace) {}
10978
11045
  }
10979
11046
 
10980
11047
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
@@ -11000,10 +11067,23 @@ class CloudScript extends script("cloud", [
11000
11067
  await session.ask(question);
11001
11068
  }
11002
11069
  async downloadEnv(workspace) {
11003
- await this.cloudRunner.downloadEnv(workspace);
11070
+ const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
11071
+ if (workspaceId) {
11072
+ const cloudApi2 = await CloudApi.fromHost();
11073
+ await this.cloudRunner.downloadEnv(cloudApi2, workspace, workspaceId);
11074
+ return;
11075
+ }
11076
+ await this.cloudRunner.downloadEnvByScp(workspace);
11004
11077
  }
11005
11078
  async uploadEnv(workspace) {
11006
- await this.cloudRunner.uploadEnv(workspace);
11079
+ const workspaceId = workspace.getWorkspaceId({ allowEmpty: true });
11080
+ const { path: path39 } = await this.cloudRunner.gatherEnvFiles(workspace);
11081
+ if (workspaceId) {
11082
+ const cloudApi2 = await CloudApi.fromHost();
11083
+ await this.cloudRunner.uploadEnv(cloudApi2, workspaceId, path39);
11084
+ return;
11085
+ }
11086
+ await this.cloudRunner.uploadEnvByScp(workspace, path39);
11007
11087
  }
11008
11088
  async deployAkan(workspace, { test = true, registryUrl } = {}) {
11009
11089
  const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
@@ -11042,7 +11122,10 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
11042
11122
  resetLlm: target({ desc: "Reset LLM configuration to default" }).with(Workspace).exec(function(workspace) {
11043
11123
  this.cloudScript.resetLlm(workspace);
11044
11124
  }),
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) {
11125
+ ask: target({
11126
+ devOnly: true,
11127
+ desc: "Ask AI assistant a question about your project"
11128
+ }).option("question", String, { ask: "question to ask" }).with(Workspace).exec(async function(question, workspace) {
11046
11129
  await this.cloudScript.ask(question, workspace);
11047
11130
  }),
11048
11131
  deployAkan: target({
@@ -11077,10 +11160,14 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
11077
11160
  registryUrl: resolveRegistryUrl(registry)
11078
11161
  });
11079
11162
  }),
11080
- downloadEnv: target({ desc: "Download environment variables from cloud" }).with(Workspace).exec(async function(workspace) {
11163
+ downloadEnv: target({
11164
+ desc: "Download environment variables from cloud or SCP server"
11165
+ }).with(Workspace).exec(async function(workspace) {
11081
11166
  await this.cloudScript.downloadEnv(workspace);
11082
11167
  }),
11083
- uploadEnv: target({ desc: "Upload environment variables to cloud" }).with(Workspace).exec(async function(workspace) {
11168
+ uploadEnv: target({
11169
+ desc: "Upload environment variables to cloud or SCP server"
11170
+ }).with(Workspace).exec(async function(workspace) {
11084
11171
  await this.cloudScript.uploadEnv(workspace);
11085
11172
  })
11086
11173
  })) {
@@ -11554,7 +11641,7 @@ class LocalRegistryCommand extends command("local-registry", [LocalRegistryScrip
11554
11641
  import { lowerlize } from "akanjs/common";
11555
11642
 
11556
11643
  // pkgs/@akanjs/cli/module/module.script.ts
11557
- import { input as input5 } from "@inquirer/prompts";
11644
+ import { input as input6 } from "@inquirer/prompts";
11558
11645
  import { capitalize as capitalize6, randomPicks as randomPicks2 } from "akanjs/common";
11559
11646
 
11560
11647
  // pkgs/@akanjs/cli/page/page.runner.ts
@@ -11981,8 +12068,8 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
11981
12068
  const { constant, dictionary } = await this.moduleRunner.createModuleTemplate(executor);
11982
12069
  if (page && sys3.type === "app")
11983
12070
  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" });
12071
+ const modelDesc = description ?? await input6({ message: "description of module" });
12072
+ const modelSchemaDesign = schemaDescription ?? await input6({ message: "schema description of module" });
11986
12073
  const config = await sys3.getConfig();
11987
12074
  const moduleRequest = new ModuleRequest({ sysType: sys3.type, sysName: sys3.name, modelName: name, config });
11988
12075
  const constantRequestPrompt = await moduleRequest.requestModelConstant({
@@ -12153,7 +12240,7 @@ class PageCommand extends command("page", [PageScript], ({ public: target }) =>
12153
12240
  import { lowerlize as lowerlize2 } from "akanjs/common";
12154
12241
 
12155
12242
  // pkgs/@akanjs/cli/scalar/scalar.prompt.ts
12156
- import { input as input6 } from "@inquirer/prompts";
12243
+ import { input as input7 } from "@inquirer/prompts";
12157
12244
  class ScalarPrompt extends Prompter {
12158
12245
  sys;
12159
12246
  name;
@@ -12163,13 +12250,13 @@ class ScalarPrompt extends Prompter {
12163
12250
  this.name = name;
12164
12251
  }
12165
12252
  async requestUpdateConstant() {
12166
- const request = await input6({ message: `What do you want to change?` });
12253
+ const request = await input7({ message: `What do you want to change?` });
12167
12254
  return { request, validate: undefined };
12168
12255
  }
12169
12256
  async requestCreateConstant() {
12170
12257
  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" });
12258
+ const description = await input7({ message: "description of scalar" });
12259
+ const schemaDescription = await input7({ message: "schema description of scalar" });
12173
12260
  await this.sys.applyTemplate({
12174
12261
  basePath: "./lib/__scalar",
12175
12262
  template: "__scalar",