@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/guidelines/modelConstant/modelConstant.generate.json +1 -0
- package/guidelines/modelDictionary/modelDictionary.generate.json +1 -0
- package/guidelines/scalarConstant/scalarConstant.generate.json +1 -0
- package/guidelines/scalarDictionary/scalarDictionary.generate.json +1 -0
- package/incrementalBuilder.proc.js +795 -590
- package/index.js +1086 -682
- package/package.json +3 -2
- package/templates/module/__Model__.Unit.tsx +5 -2
- package/typecheck.proc.js +19 -31
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/
|
|
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/
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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 = [
|
|
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({
|
|
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
|
-
|
|
516
|
-
return akanConfig.llm ?? null;
|
|
389
|
+
return await GlobalConfig.getLlmConfig();
|
|
517
390
|
}
|
|
518
391
|
static async setLlmConfig(llmConfig) {
|
|
519
|
-
|
|
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({
|
|
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...", {
|
|
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, {
|
|
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 = ""
|
|
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
|
|
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, {
|
|
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
|
-
|
|
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,
|
|
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,
|
|
676
|
-
|
|
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...`, {
|
|
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
|
|
684
|
-
const
|
|
685
|
-
const
|
|
686
|
-
|
|
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
|
|
689
|
-
if (
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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.#
|
|
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
|
-
#
|
|
1137
|
-
const configPath2 = path3.join(dir, "
|
|
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
|
-
|
|
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
|
-
|
|
1173
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1174
|
+
if (!existsSync(resolvedFilePath))
|
|
1150
1175
|
throw new Error(`File not found: ${filePath}`);
|
|
1151
|
-
return
|
|
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
|
|
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 ? "
|
|
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("
|
|
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
|
-
}), {
|
|
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
|
|
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
|
-
|
|
1267
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1268
|
+
if (!existsSync(resolvedFilePath))
|
|
1240
1269
|
throw new Error(`File not found: ${filePath}`);
|
|
1241
|
-
|
|
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
|
-
|
|
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((
|
|
1635
|
-
addViolation(
|
|
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((
|
|
1642
|
-
addViolation(path5.join("lib",
|
|
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((
|
|
1645
|
-
const serviceDirs = libRoot.dirs.filter((
|
|
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((
|
|
1649
|
-
...serviceDirs.map((
|
|
1650
|
-
...scalarDirs.map((
|
|
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((
|
|
1661
|
-
violations.push(`${getScanPath(exec, path5.join(modulePath,
|
|
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 (
|
|
1761
|
-
const name =
|
|
1762
|
-
const filenames = await exec.readdir(path5.join("lib",
|
|
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([
|
|
2332
|
-
|
|
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([
|
|
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([
|
|
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
|
|
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
|
-
|
|
2529
|
+
Logger3.raw(chalk4.dim(data.toString()));
|
|
2470
2530
|
}
|
|
2471
2531
|
#stderr(data) {
|
|
2472
|
-
|
|
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({
|
|
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({
|
|
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 =
|
|
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({
|
|
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({
|
|
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 =
|
|
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({
|
|
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 (
|
|
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, {
|
|
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: {
|
|
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({
|
|
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
|
|
2761
|
-
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${
|
|
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, {
|
|
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
|
|
2774
|
-
if (!await FileSys.dirExists(
|
|
2775
|
-
await mkdir2(
|
|
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({
|
|
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({
|
|
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]) => [
|
|
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, {
|
|
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 {
|
|
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([
|
|
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([
|
|
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) => [
|
|
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 (
|
|
2942
|
-
const dirs = await this.readdir(
|
|
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(
|
|
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 (
|
|
2967
|
-
const dirs = await this.readdir(
|
|
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(
|
|
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({
|
|
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, {
|
|
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) => [
|
|
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 [
|
|
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]) => [
|
|
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({
|
|
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([
|
|
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({
|
|
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({
|
|
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, {
|
|
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([
|
|
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({
|
|
3358
|
-
|
|
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({
|
|
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 = {
|
|
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([
|
|
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([
|
|
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: {
|
|
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([
|
|
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([
|
|
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
|
|
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
|
|
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
|
|
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
|
|
4467
|
+
import { Logger as Logger6 } from "akanjs/common";
|
|
4203
4468
|
|
|
4204
4469
|
class ApplicationBuildReporter {
|
|
4205
4470
|
static create() {
|
|
4206
4471
|
return {
|
|
4207
|
-
phaseDone: (phase) =>
|
|
4472
|
+
phaseDone: (phase) => Logger6.rawLog(ApplicationBuildReporter.formatPhaseLine(phase))
|
|
4208
4473
|
};
|
|
4209
4474
|
}
|
|
4210
4475
|
static printSummary(result) {
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8050
|
+
const logger = new Logger9("uploadRelease");
|
|
7786
8051
|
const basePath2 = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
|
|
7787
|
-
const httpClient = new
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
9695
|
-
const candidates = [
|
|
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({
|
|
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({
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10316
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
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
|
-
|
|
11113
|
+
Logger14.rawLog(chalk7.bold(`
|
|
10789
11114
|
${chalk7.green("\u27A4")} Authentication Required`));
|
|
10790
|
-
|
|
10791
|
-
|
|
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
|
-
|
|
11126
|
+
Logger14.rawLog(qrcode);
|
|
10802
11127
|
await openBrowser(signinUrl);
|
|
10803
|
-
|
|
11128
|
+
Logger14.rawLog(chalk7.dim("Opening browser..."));
|
|
10804
11129
|
} catch {
|
|
10805
|
-
|
|
11130
|
+
Logger14.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
|
|
10806
11131
|
}
|
|
10807
|
-
|
|
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
|
|
10811
|
-
const
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10835
|
-
|
|
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
|
-
|
|
11164
|
+
Logger14.rawLog(chalk7.yellow.bold(`
|
|
10839
11165
|
\u26A0\uFE0F No active session found`));
|
|
10840
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10874
|
-
|
|
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
|
-
|
|
11214
|
+
Logger14.error("Deployment cancelled");
|
|
10889
11215
|
return;
|
|
10890
11216
|
}
|
|
10891
11217
|
}
|
|
10892
11218
|
await Promise.all(akanPkgs.map(async (library) => {
|
|
10893
|
-
|
|
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
|
-
|
|
11231
|
+
Logger14.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
|
|
10906
11232
|
}));
|
|
10907
|
-
|
|
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
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
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
|
-
|
|
10974
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
11985
|
-
const modelSchemaDesign = schemaDescription ?? await
|
|
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
|
|
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
|
|
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
|
|
12172
|
-
const schemaDescription = await
|
|
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
|
|
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:
|
|
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,
|
|
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 ${
|
|
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 ${
|
|
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:
|
|
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:
|
|
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(
|
|
12525
|
-
|
|
12526
|
-
\uD83C\uDF89 Welcome aboard! Workspace created in ${
|
|
12527
|
-
|
|
12528
|
-
|
|
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 } = {}) {
|