@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
|
@@ -1,328 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
function __accessProp(key) {
|
|
8
|
-
return this[key];
|
|
9
|
-
}
|
|
10
|
-
var __toESMCache_node;
|
|
11
|
-
var __toESMCache_esm;
|
|
12
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
-
var canCache = mod != null && typeof mod === "object";
|
|
14
|
-
if (canCache) {
|
|
15
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
-
var cached = cache.get(mod);
|
|
17
|
-
if (cached)
|
|
18
|
-
return cached;
|
|
19
|
-
}
|
|
20
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
-
for (let key of __getOwnPropNames(mod))
|
|
23
|
-
if (!__hasOwnProp.call(to, key))
|
|
24
|
-
__defProp(to, key, {
|
|
25
|
-
get: __accessProp.bind(mod, key),
|
|
26
|
-
enumerable: true
|
|
27
|
-
});
|
|
28
|
-
if (canCache)
|
|
29
|
-
cache.set(mod, to);
|
|
30
|
-
return to;
|
|
31
|
-
};
|
|
32
|
-
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
2
|
var __require = import.meta.require;
|
|
34
3
|
|
|
35
|
-
// node_modules/dayjs/dayjs.min.js
|
|
36
|
-
var require_dayjs_min = __commonJS((exports, module) => {
|
|
37
|
-
(function(t, e) {
|
|
38
|
-
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();
|
|
39
|
-
})(exports, function() {
|
|
40
|
-
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) {
|
|
41
|
-
var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
|
|
42
|
-
return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
|
|
43
|
-
} }, m = function(t2, e2, n2) {
|
|
44
|
-
var r2 = String(t2);
|
|
45
|
-
return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
|
|
46
|
-
}, v = { s: m, z: function(t2) {
|
|
47
|
-
var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
|
|
48
|
-
return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
|
|
49
|
-
}, m: function t2(e2, n2) {
|
|
50
|
-
if (e2.date() < n2.date())
|
|
51
|
-
return -t2(n2, e2);
|
|
52
|
-
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);
|
|
53
|
-
return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
|
|
54
|
-
}, a: function(t2) {
|
|
55
|
-
return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
|
|
56
|
-
}, p: function(t2) {
|
|
57
|
-
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$/, "");
|
|
58
|
-
}, u: function(t2) {
|
|
59
|
-
return t2 === undefined;
|
|
60
|
-
} }, g = "en", D = {};
|
|
61
|
-
D[g] = M;
|
|
62
|
-
var p = "$isDayjsObject", S = function(t2) {
|
|
63
|
-
return t2 instanceof _ || !(!t2 || !t2[p]);
|
|
64
|
-
}, w = function t2(e2, n2, r2) {
|
|
65
|
-
var i2;
|
|
66
|
-
if (!e2)
|
|
67
|
-
return g;
|
|
68
|
-
if (typeof e2 == "string") {
|
|
69
|
-
var s2 = e2.toLowerCase();
|
|
70
|
-
D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
|
|
71
|
-
var u2 = e2.split("-");
|
|
72
|
-
if (!i2 && u2.length > 1)
|
|
73
|
-
return t2(u2[0]);
|
|
74
|
-
} else {
|
|
75
|
-
var a2 = e2.name;
|
|
76
|
-
D[a2] = e2, i2 = a2;
|
|
77
|
-
}
|
|
78
|
-
return !r2 && i2 && (g = i2), i2 || !r2 && g;
|
|
79
|
-
}, O = function(t2, e2) {
|
|
80
|
-
if (S(t2))
|
|
81
|
-
return t2.clone();
|
|
82
|
-
var n2 = typeof e2 == "object" ? e2 : {};
|
|
83
|
-
return n2.date = t2, n2.args = arguments, new _(n2);
|
|
84
|
-
}, b = v;
|
|
85
|
-
b.l = w, b.i = S, b.w = function(t2, e2) {
|
|
86
|
-
return O(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
|
|
87
|
-
};
|
|
88
|
-
var _ = function() {
|
|
89
|
-
function M2(t2) {
|
|
90
|
-
this.$L = w(t2.locale, null, true), this.parse(t2), this.$x = this.$x || t2.x || {}, this[p] = true;
|
|
91
|
-
}
|
|
92
|
-
var m2 = M2.prototype;
|
|
93
|
-
return m2.parse = function(t2) {
|
|
94
|
-
this.$d = function(t3) {
|
|
95
|
-
var { date: e2, utc: n2 } = t3;
|
|
96
|
-
if (e2 === null)
|
|
97
|
-
return new Date(NaN);
|
|
98
|
-
if (b.u(e2))
|
|
99
|
-
return new Date;
|
|
100
|
-
if (e2 instanceof Date)
|
|
101
|
-
return new Date(e2);
|
|
102
|
-
if (typeof e2 == "string" && !/Z$/i.test(e2)) {
|
|
103
|
-
var r2 = e2.match($2);
|
|
104
|
-
if (r2) {
|
|
105
|
-
var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
|
|
106
|
-
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);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return new Date(e2);
|
|
110
|
-
}(t2), this.init();
|
|
111
|
-
}, m2.init = function() {
|
|
112
|
-
var t2 = this.$d;
|
|
113
|
-
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();
|
|
114
|
-
}, m2.$utils = function() {
|
|
115
|
-
return b;
|
|
116
|
-
}, m2.isValid = function() {
|
|
117
|
-
return !(this.$d.toString() === l);
|
|
118
|
-
}, m2.isSame = function(t2, e2) {
|
|
119
|
-
var n2 = O(t2);
|
|
120
|
-
return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
|
|
121
|
-
}, m2.isAfter = function(t2, e2) {
|
|
122
|
-
return O(t2) < this.startOf(e2);
|
|
123
|
-
}, m2.isBefore = function(t2, e2) {
|
|
124
|
-
return this.endOf(e2) < O(t2);
|
|
125
|
-
}, m2.$g = function(t2, e2, n2) {
|
|
126
|
-
return b.u(t2) ? this[e2] : this.set(n2, t2);
|
|
127
|
-
}, m2.unix = function() {
|
|
128
|
-
return Math.floor(this.valueOf() / 1000);
|
|
129
|
-
}, m2.valueOf = function() {
|
|
130
|
-
return this.$d.getTime();
|
|
131
|
-
}, m2.startOf = function(t2, e2) {
|
|
132
|
-
var n2 = this, r2 = !!b.u(e2) || e2, f2 = b.p(t2), l2 = function(t3, e3) {
|
|
133
|
-
var i2 = b.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
|
|
134
|
-
return r2 ? i2 : i2.endOf(a);
|
|
135
|
-
}, $3 = function(t3, e3) {
|
|
136
|
-
return b.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
|
|
137
|
-
}, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
|
|
138
|
-
switch (f2) {
|
|
139
|
-
case h:
|
|
140
|
-
return r2 ? l2(1, 0) : l2(31, 11);
|
|
141
|
-
case c:
|
|
142
|
-
return r2 ? l2(1, M3) : l2(0, M3 + 1);
|
|
143
|
-
case o:
|
|
144
|
-
var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
|
|
145
|
-
return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
|
|
146
|
-
case a:
|
|
147
|
-
case d:
|
|
148
|
-
return $3(v2 + "Hours", 0);
|
|
149
|
-
case u:
|
|
150
|
-
return $3(v2 + "Minutes", 1);
|
|
151
|
-
case s:
|
|
152
|
-
return $3(v2 + "Seconds", 2);
|
|
153
|
-
case i:
|
|
154
|
-
return $3(v2 + "Milliseconds", 3);
|
|
155
|
-
default:
|
|
156
|
-
return this.clone();
|
|
157
|
-
}
|
|
158
|
-
}, m2.endOf = function(t2) {
|
|
159
|
-
return this.startOf(t2, false);
|
|
160
|
-
}, m2.$set = function(t2, e2) {
|
|
161
|
-
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;
|
|
162
|
-
if (o2 === c || o2 === h) {
|
|
163
|
-
var y2 = this.clone().set(d, 1);
|
|
164
|
-
y2.$d[l2]($3), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
|
|
165
|
-
} else
|
|
166
|
-
l2 && this.$d[l2]($3);
|
|
167
|
-
return this.init(), this;
|
|
168
|
-
}, m2.set = function(t2, e2) {
|
|
169
|
-
return this.clone().$set(t2, e2);
|
|
170
|
-
}, m2.get = function(t2) {
|
|
171
|
-
return this[b.p(t2)]();
|
|
172
|
-
}, m2.add = function(r2, f2) {
|
|
173
|
-
var d2, l2 = this;
|
|
174
|
-
r2 = Number(r2);
|
|
175
|
-
var $3 = b.p(f2), y2 = function(t2) {
|
|
176
|
-
var e2 = O(l2);
|
|
177
|
-
return b.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
|
|
178
|
-
};
|
|
179
|
-
if ($3 === c)
|
|
180
|
-
return this.set(c, this.$M + r2);
|
|
181
|
-
if ($3 === h)
|
|
182
|
-
return this.set(h, this.$y + r2);
|
|
183
|
-
if ($3 === a)
|
|
184
|
-
return y2(1);
|
|
185
|
-
if ($3 === o)
|
|
186
|
-
return y2(7);
|
|
187
|
-
var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$3] || 1, m3 = this.$d.getTime() + r2 * M3;
|
|
188
|
-
return b.w(m3, this);
|
|
189
|
-
}, m2.subtract = function(t2, e2) {
|
|
190
|
-
return this.add(-1 * t2, e2);
|
|
191
|
-
}, m2.format = function(t2) {
|
|
192
|
-
var e2 = this, n2 = this.$locale();
|
|
193
|
-
if (!this.isValid())
|
|
194
|
-
return n2.invalidDate || l;
|
|
195
|
-
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) {
|
|
196
|
-
return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
|
|
197
|
-
}, d2 = function(t3) {
|
|
198
|
-
return b.s(s2 % 12 || 12, t3, "0");
|
|
199
|
-
}, $3 = f2 || function(t3, e3, n3) {
|
|
200
|
-
var r3 = t3 < 12 ? "AM" : "PM";
|
|
201
|
-
return n3 ? r3.toLowerCase() : r3;
|
|
202
|
-
};
|
|
203
|
-
return r2.replace(y, function(t3, r3) {
|
|
204
|
-
return r3 || function(t4) {
|
|
205
|
-
switch (t4) {
|
|
206
|
-
case "YY":
|
|
207
|
-
return String(e2.$y).slice(-2);
|
|
208
|
-
case "YYYY":
|
|
209
|
-
return b.s(e2.$y, 4, "0");
|
|
210
|
-
case "M":
|
|
211
|
-
return a2 + 1;
|
|
212
|
-
case "MM":
|
|
213
|
-
return b.s(a2 + 1, 2, "0");
|
|
214
|
-
case "MMM":
|
|
215
|
-
return h2(n2.monthsShort, a2, c2, 3);
|
|
216
|
-
case "MMMM":
|
|
217
|
-
return h2(c2, a2);
|
|
218
|
-
case "D":
|
|
219
|
-
return e2.$D;
|
|
220
|
-
case "DD":
|
|
221
|
-
return b.s(e2.$D, 2, "0");
|
|
222
|
-
case "d":
|
|
223
|
-
return String(e2.$W);
|
|
224
|
-
case "dd":
|
|
225
|
-
return h2(n2.weekdaysMin, e2.$W, o2, 2);
|
|
226
|
-
case "ddd":
|
|
227
|
-
return h2(n2.weekdaysShort, e2.$W, o2, 3);
|
|
228
|
-
case "dddd":
|
|
229
|
-
return o2[e2.$W];
|
|
230
|
-
case "H":
|
|
231
|
-
return String(s2);
|
|
232
|
-
case "HH":
|
|
233
|
-
return b.s(s2, 2, "0");
|
|
234
|
-
case "h":
|
|
235
|
-
return d2(1);
|
|
236
|
-
case "hh":
|
|
237
|
-
return d2(2);
|
|
238
|
-
case "a":
|
|
239
|
-
return $3(s2, u2, true);
|
|
240
|
-
case "A":
|
|
241
|
-
return $3(s2, u2, false);
|
|
242
|
-
case "m":
|
|
243
|
-
return String(u2);
|
|
244
|
-
case "mm":
|
|
245
|
-
return b.s(u2, 2, "0");
|
|
246
|
-
case "s":
|
|
247
|
-
return String(e2.$s);
|
|
248
|
-
case "ss":
|
|
249
|
-
return b.s(e2.$s, 2, "0");
|
|
250
|
-
case "SSS":
|
|
251
|
-
return b.s(e2.$ms, 3, "0");
|
|
252
|
-
case "Z":
|
|
253
|
-
return i2;
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
}(t3) || i2.replace(":", "");
|
|
257
|
-
});
|
|
258
|
-
}, m2.utcOffset = function() {
|
|
259
|
-
return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
|
|
260
|
-
}, m2.diff = function(r2, d2, l2) {
|
|
261
|
-
var $3, y2 = this, M3 = b.p(d2), m3 = O(r2), v2 = (m3.utcOffset() - this.utcOffset()) * e, g2 = this - m3, D2 = function() {
|
|
262
|
-
return b.m(y2, m3);
|
|
263
|
-
};
|
|
264
|
-
switch (M3) {
|
|
265
|
-
case h:
|
|
266
|
-
$3 = D2() / 12;
|
|
267
|
-
break;
|
|
268
|
-
case c:
|
|
269
|
-
$3 = D2();
|
|
270
|
-
break;
|
|
271
|
-
case f:
|
|
272
|
-
$3 = D2() / 3;
|
|
273
|
-
break;
|
|
274
|
-
case o:
|
|
275
|
-
$3 = (g2 - v2) / 604800000;
|
|
276
|
-
break;
|
|
277
|
-
case a:
|
|
278
|
-
$3 = (g2 - v2) / 86400000;
|
|
279
|
-
break;
|
|
280
|
-
case u:
|
|
281
|
-
$3 = g2 / n;
|
|
282
|
-
break;
|
|
283
|
-
case s:
|
|
284
|
-
$3 = g2 / e;
|
|
285
|
-
break;
|
|
286
|
-
case i:
|
|
287
|
-
$3 = g2 / t;
|
|
288
|
-
break;
|
|
289
|
-
default:
|
|
290
|
-
$3 = g2;
|
|
291
|
-
}
|
|
292
|
-
return l2 ? $3 : b.a($3);
|
|
293
|
-
}, m2.daysInMonth = function() {
|
|
294
|
-
return this.endOf(c).$D;
|
|
295
|
-
}, m2.$locale = function() {
|
|
296
|
-
return D[this.$L];
|
|
297
|
-
}, m2.locale = function(t2, e2) {
|
|
298
|
-
if (!t2)
|
|
299
|
-
return this.$L;
|
|
300
|
-
var n2 = this.clone(), r2 = w(t2, e2, true);
|
|
301
|
-
return r2 && (n2.$L = r2), n2;
|
|
302
|
-
}, m2.clone = function() {
|
|
303
|
-
return b.w(this.$d, this);
|
|
304
|
-
}, m2.toDate = function() {
|
|
305
|
-
return new Date(this.valueOf());
|
|
306
|
-
}, m2.toJSON = function() {
|
|
307
|
-
return this.isValid() ? this.toISOString() : null;
|
|
308
|
-
}, m2.toISOString = function() {
|
|
309
|
-
return this.$d.toISOString();
|
|
310
|
-
}, m2.toString = function() {
|
|
311
|
-
return this.$d.toUTCString();
|
|
312
|
-
}, M2;
|
|
313
|
-
}(), Y = _.prototype;
|
|
314
|
-
return O.prototype = Y, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", c], ["$y", h], ["$D", d]].forEach(function(t2) {
|
|
315
|
-
Y[t2[1]] = function(e2) {
|
|
316
|
-
return this.$g(e2, t2[0], t2[1]);
|
|
317
|
-
};
|
|
318
|
-
}), O.extend = function(t2, e2) {
|
|
319
|
-
return t2.$i || (t2(e2, _, O), t2.$i = true), O;
|
|
320
|
-
}, O.locale = w, O.isDayjs = S, O.unix = function(t2) {
|
|
321
|
-
return O(1000 * t2);
|
|
322
|
-
}, O.en = D[g], O.Ls = D, O.p = {}, O;
|
|
323
|
-
});
|
|
324
|
-
});
|
|
325
|
-
|
|
326
4
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
|
|
327
5
|
import path37 from "path";
|
|
328
6
|
|
|
@@ -339,10 +17,7 @@ import { ChatOpenAI } from "@langchain/openai";
|
|
|
339
17
|
import { Logger as Logger2 } from "akanjs/common";
|
|
340
18
|
import chalk from "chalk";
|
|
341
19
|
|
|
342
|
-
// pkgs/@akanjs/devkit/
|
|
343
|
-
import { mkdir } from "fs/promises";
|
|
344
|
-
|
|
345
|
-
// pkgs/@akanjs/devkit/constants.ts
|
|
20
|
+
// pkgs/@akanjs/devkit/cloud/constants.ts
|
|
346
21
|
var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
|
|
347
22
|
var configPath = `${basePath}/config.json`;
|
|
348
23
|
var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
|
|
@@ -350,9 +25,14 @@ var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE ===
|
|
|
350
25
|
var defaultHostConfig = {};
|
|
351
26
|
var defaultAkanGlobalConfig = {
|
|
352
27
|
cloudHost: {},
|
|
28
|
+
remoteEnvServers: {},
|
|
353
29
|
llm: null
|
|
354
30
|
};
|
|
355
31
|
|
|
32
|
+
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
33
|
+
import { mkdir } from "fs/promises";
|
|
34
|
+
import dayjs from "dayjs";
|
|
35
|
+
|
|
356
36
|
// pkgs/@akanjs/devkit/fileSys.ts
|
|
357
37
|
import { stat } from "fs/promises";
|
|
358
38
|
import { Logger } from "akanjs/common";
|
|
@@ -391,35 +71,198 @@ class FileSys {
|
|
|
391
71
|
}
|
|
392
72
|
}
|
|
393
73
|
|
|
394
|
-
// pkgs/@akanjs/devkit/
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const akanConfig = await getAkanGlobalConfig();
|
|
406
|
-
return akanConfig.cloudHost[host] ?? defaultHostConfig;
|
|
407
|
-
};
|
|
408
|
-
var setHostConfig = async (host = akanCloudHost, config = {}) => {
|
|
409
|
-
const akanConfig = await getAkanGlobalConfig();
|
|
410
|
-
akanConfig.cloudHost[host] = config;
|
|
411
|
-
await setAkanGlobalConfig(akanConfig);
|
|
412
|
-
};
|
|
413
|
-
var getSelf = async (token) => {
|
|
414
|
-
try {
|
|
415
|
-
const res = await fetch(`${akanCloudUrl}/user/getSelf`, { headers: { Authorization: `Bearer ${token}` } });
|
|
416
|
-
const user = await res.json();
|
|
417
|
-
return user;
|
|
418
|
-
} catch (e) {
|
|
419
|
-
return null;
|
|
74
|
+
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
75
|
+
class GlobalConfig {
|
|
76
|
+
static async#getAkanGlobalConfig() {
|
|
77
|
+
const exists = await FileSys.fileExists(configPath);
|
|
78
|
+
const akanConfig = exists ? await FileSys.readJson(configPath) : {};
|
|
79
|
+
return {
|
|
80
|
+
...defaultAkanGlobalConfig,
|
|
81
|
+
...akanConfig,
|
|
82
|
+
cloudHost: akanConfig.cloudHost ?? defaultAkanGlobalConfig.cloudHost,
|
|
83
|
+
remoteEnvServers: akanConfig.remoteEnvServers ?? defaultAkanGlobalConfig.remoteEnvServers
|
|
84
|
+
};
|
|
420
85
|
}
|
|
421
|
-
|
|
86
|
+
static async#setAkanGlobalConfig(akanConfig) {
|
|
87
|
+
await mkdir(basePath, { recursive: true });
|
|
88
|
+
await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
|
|
89
|
+
}
|
|
90
|
+
static async getHostConfig(host = akanCloudHost) {
|
|
91
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
92
|
+
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? defaultHostConfig);
|
|
93
|
+
}
|
|
94
|
+
static async setHostConfig(host = akanCloudHost, config = {}) {
|
|
95
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
96
|
+
akanConfig.cloudHost[host] = GlobalConfig.toHostConfigDto(config);
|
|
97
|
+
await GlobalConfig.#setAkanGlobalConfig(akanConfig);
|
|
98
|
+
}
|
|
99
|
+
static async getLlmConfig() {
|
|
100
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
101
|
+
return akanConfig.llm ?? null;
|
|
102
|
+
}
|
|
103
|
+
static async setLlmConfig(llmConfig) {
|
|
104
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
105
|
+
await GlobalConfig.#setAkanGlobalConfig({ ...akanConfig, llm: llmConfig });
|
|
106
|
+
}
|
|
107
|
+
static async getRemoteEnvServers() {
|
|
108
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
109
|
+
return akanConfig.remoteEnvServers;
|
|
110
|
+
}
|
|
111
|
+
static async setRemoteEnvServer(name, config) {
|
|
112
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
113
|
+
await GlobalConfig.#setAkanGlobalConfig({
|
|
114
|
+
...akanConfig,
|
|
115
|
+
remoteEnvServers: {
|
|
116
|
+
...akanConfig.remoteEnvServers,
|
|
117
|
+
[name]: config
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
static async removeRemoteEnvServer(name) {
|
|
122
|
+
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
123
|
+
const { [name]: _, ...remoteEnvServers } = akanConfig.remoteEnvServers;
|
|
124
|
+
await GlobalConfig.#setAkanGlobalConfig({
|
|
125
|
+
...akanConfig,
|
|
126
|
+
remoteEnvServers
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
static needRefreshToken(accessToken) {
|
|
130
|
+
return !!accessToken?.expiresAt?.isBefore(dayjs().add(1, "hour"));
|
|
131
|
+
}
|
|
132
|
+
static toAccessToken(accessToken) {
|
|
133
|
+
return {
|
|
134
|
+
jwt: accessToken.jwt,
|
|
135
|
+
refreshToken: accessToken.refreshToken ?? null,
|
|
136
|
+
expiresAt: accessToken.expiresAt ? dayjs(accessToken.expiresAt) : null
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
static toAccessTokenDto(accessToken) {
|
|
140
|
+
return {
|
|
141
|
+
jwt: accessToken.jwt,
|
|
142
|
+
refreshToken: accessToken.refreshToken ?? null,
|
|
143
|
+
expiresAt: accessToken.expiresAt?.toString() ?? null
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
static toHostConfigDto(hostConfig) {
|
|
147
|
+
return {
|
|
148
|
+
auth: {
|
|
149
|
+
accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
|
|
150
|
+
self: hostConfig.auth?.self
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
static toHostConfig(hostConfigDto) {
|
|
155
|
+
return {
|
|
156
|
+
auth: {
|
|
157
|
+
accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
|
|
158
|
+
self: hostConfigDto.auth?.self
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
422
163
|
|
|
164
|
+
// pkgs/@akanjs/devkit/cloud/cloudApi.ts
|
|
165
|
+
class HttpClient {
|
|
166
|
+
baseUrl;
|
|
167
|
+
headers = {};
|
|
168
|
+
constructor(baseUrl, headers = {}) {
|
|
169
|
+
this.baseUrl = baseUrl;
|
|
170
|
+
this.headers = headers;
|
|
171
|
+
}
|
|
172
|
+
async get(url, { headers } = {}) {
|
|
173
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
174
|
+
headers: {
|
|
175
|
+
"Content-Type": "application/json",
|
|
176
|
+
...this.headers,
|
|
177
|
+
...headers
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return response.json();
|
|
181
|
+
}
|
|
182
|
+
async getFile(url, localPath, headers) {
|
|
183
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
184
|
+
headers: { ...this.headers, ...headers }
|
|
185
|
+
});
|
|
186
|
+
if (!response.ok)
|
|
187
|
+
throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
|
|
188
|
+
await Bun.write(localPath, response);
|
|
189
|
+
}
|
|
190
|
+
async post(url, data, { headers } = {}) {
|
|
191
|
+
const isFormData = data instanceof FormData;
|
|
192
|
+
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
193
|
+
method: "POST",
|
|
194
|
+
body: isFormData ? data : JSON.stringify(data),
|
|
195
|
+
headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
|
|
196
|
+
});
|
|
197
|
+
return response.json();
|
|
198
|
+
}
|
|
199
|
+
setHeaders(headers) {
|
|
200
|
+
Object.assign(this.headers, headers);
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
class CloudApi {
|
|
206
|
+
#api;
|
|
207
|
+
#accessToken = null;
|
|
208
|
+
static async fromHost(host) {
|
|
209
|
+
const hostConfig = await GlobalConfig.getHostConfig(host);
|
|
210
|
+
return new CloudApi(hostConfig);
|
|
211
|
+
}
|
|
212
|
+
constructor(hostConfig) {
|
|
213
|
+
const host = akanCloudHost;
|
|
214
|
+
this.#api = new HttpClient(`${host}/api`);
|
|
215
|
+
this.#accessToken = hostConfig.auth?.accessToken ?? null;
|
|
216
|
+
if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
|
|
217
|
+
this.#api.setHeaders({
|
|
218
|
+
Authorization: `Bearer ${this.#accessToken.jwt}`
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
async uploadEnv(devProjectId, file) {
|
|
222
|
+
const formData = new FormData;
|
|
223
|
+
formData.append("devProjectId", devProjectId);
|
|
224
|
+
formData.append("file", file);
|
|
225
|
+
const data = await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
|
|
226
|
+
return data;
|
|
227
|
+
}
|
|
228
|
+
async downloadEnv(devProjectId, localPath) {
|
|
229
|
+
await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
|
|
230
|
+
}
|
|
231
|
+
async getRemoteAuthToken(remoteId) {
|
|
232
|
+
try {
|
|
233
|
+
if (this.#accessToken) {
|
|
234
|
+
if (GlobalConfig.needRefreshToken(this.#accessToken))
|
|
235
|
+
return await this.refreshAuthToken();
|
|
236
|
+
else
|
|
237
|
+
return await this.refreshAuthToken();
|
|
238
|
+
}
|
|
239
|
+
const accessToken = await this.#api.get(`/getRemoteAuthToken/${remoteId}`);
|
|
240
|
+
this.#accessToken = GlobalConfig.toAccessToken(accessToken);
|
|
241
|
+
this.#api.setHeaders({
|
|
242
|
+
Authorization: `Bearer ${this.#accessToken.jwt}`
|
|
243
|
+
});
|
|
244
|
+
return this.#accessToken;
|
|
245
|
+
} catch (_) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async refreshAuthToken() {
|
|
250
|
+
const response = await this.#api.post(`/refreshRemoteAuthToken`, {
|
|
251
|
+
refreshToken: this.#accessToken?.refreshToken
|
|
252
|
+
});
|
|
253
|
+
this.#accessToken = GlobalConfig.toAccessToken(response);
|
|
254
|
+
this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
|
|
255
|
+
return this.#accessToken;
|
|
256
|
+
}
|
|
257
|
+
async getRemoteSelf() {
|
|
258
|
+
try {
|
|
259
|
+
const data = await this.#api.get(`/getRemoteSelf`);
|
|
260
|
+
return data;
|
|
261
|
+
} catch {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
423
266
|
// pkgs/@akanjs/devkit/spinner.ts
|
|
424
267
|
import ora from "ora";
|
|
425
268
|
|
|
@@ -482,12 +325,43 @@ class Spinner {
|
|
|
482
325
|
|
|
483
326
|
// pkgs/@akanjs/devkit/aiEditor.ts
|
|
484
327
|
var MAX_ASK_TRY = 300;
|
|
485
|
-
var supportedLlmModels = [
|
|
328
|
+
var supportedLlmModels = [
|
|
329
|
+
"deepseek-chat",
|
|
330
|
+
"deepseek-reasoner"
|
|
331
|
+
];
|
|
332
|
+
var parseTypescriptFileBlocks = (text) => {
|
|
333
|
+
const fileBlocks = [];
|
|
334
|
+
const codeBlockRegex = /```(?:typescript|ts|tsx)\s*\n([\s\S]*?)```/gi;
|
|
335
|
+
const filePathRegex = /^\s*\/\/\s*File:\s*(.+?)\s*$/im;
|
|
336
|
+
for (const codeBlock of text.matchAll(codeBlockRegex)) {
|
|
337
|
+
const content = codeBlock[1]?.trim();
|
|
338
|
+
if (!content)
|
|
339
|
+
continue;
|
|
340
|
+
const filePath = filePathRegex.exec(content)?.[1]?.trim();
|
|
341
|
+
if (!filePath)
|
|
342
|
+
continue;
|
|
343
|
+
fileBlocks.push({
|
|
344
|
+
filePath,
|
|
345
|
+
content: content.replace(filePathRegex, "").trim()
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return fileBlocks;
|
|
349
|
+
};
|
|
350
|
+
var preserveTypescriptResponseContent = (previousContent, nextContent) => {
|
|
351
|
+
const previousWrites = parseTypescriptFileBlocks(previousContent);
|
|
352
|
+
const nextWrites = parseTypescriptFileBlocks(nextContent);
|
|
353
|
+
if (previousWrites.length > 0 && nextWrites.length === 0)
|
|
354
|
+
return previousContent;
|
|
355
|
+
return nextContent;
|
|
356
|
+
};
|
|
486
357
|
|
|
487
358
|
class AiSession {
|
|
488
359
|
static #cacheDir = "node_modules/.cache/akan/aiSession";
|
|
489
360
|
static #chat = null;
|
|
490
|
-
static async init({
|
|
361
|
+
static async init({
|
|
362
|
+
temperature = 0,
|
|
363
|
+
useExisting = true
|
|
364
|
+
} = {}) {
|
|
491
365
|
if (useExisting) {
|
|
492
366
|
const llmConfig2 = await AiSession.getLlmConfig();
|
|
493
367
|
if (llmConfig2) {
|
|
@@ -514,22 +388,24 @@ class AiSession {
|
|
|
514
388
|
return AiSession;
|
|
515
389
|
}
|
|
516
390
|
static async getLlmConfig() {
|
|
517
|
-
|
|
518
|
-
return akanConfig.llm ?? null;
|
|
391
|
+
return await GlobalConfig.getLlmConfig();
|
|
519
392
|
}
|
|
520
393
|
static async setLlmConfig(llmConfig) {
|
|
521
|
-
|
|
522
|
-
akanConfig.llm = llmConfig;
|
|
523
|
-
await setAkanGlobalConfig(akanConfig);
|
|
394
|
+
await GlobalConfig.setLlmConfig(llmConfig);
|
|
524
395
|
return AiSession;
|
|
525
396
|
}
|
|
526
397
|
static async#requestLlmConfig() {
|
|
527
|
-
const model = await select({
|
|
398
|
+
const model = await select({
|
|
399
|
+
message: "Select a LLM model",
|
|
400
|
+
choices: supportedLlmModels
|
|
401
|
+
});
|
|
528
402
|
const apiKey = await input({ message: "Enter your API key" });
|
|
529
403
|
return { model, apiKey };
|
|
530
404
|
}
|
|
531
405
|
static async#validateApiKey(modelName, apiKey) {
|
|
532
|
-
const spinner = new Spinner("Validating LLM API key...", {
|
|
406
|
+
const spinner = new Spinner("Validating LLM API key...", {
|
|
407
|
+
prefix: `\uD83E\uDD16akan-editor`
|
|
408
|
+
}).start();
|
|
533
409
|
const chat = new ChatOpenAI({
|
|
534
410
|
modelName,
|
|
535
411
|
temperature: 0,
|
|
@@ -552,7 +428,11 @@ class AiSession {
|
|
|
552
428
|
sessionKey;
|
|
553
429
|
isCacheLoaded = false;
|
|
554
430
|
workspace;
|
|
555
|
-
constructor(type, {
|
|
431
|
+
constructor(type, {
|
|
432
|
+
workspace,
|
|
433
|
+
cacheKey,
|
|
434
|
+
isContinued
|
|
435
|
+
}) {
|
|
556
436
|
this.workspace = workspace;
|
|
557
437
|
this.sessionKey = `${type}${cacheKey ? `-${cacheKey}` : ""}`;
|
|
558
438
|
if (isContinued)
|
|
@@ -593,7 +473,7 @@ class AiSession {
|
|
|
593
473
|
const humanMessage = new HumanMessage(question);
|
|
594
474
|
this.messageHistory.push(humanMessage);
|
|
595
475
|
const stream = await AiSession.#chat.stream(this.messageHistory);
|
|
596
|
-
let reasoningResponse = "", fullResponse = ""
|
|
476
|
+
let reasoningResponse = "", fullResponse = "";
|
|
597
477
|
for await (const chunk of stream) {
|
|
598
478
|
if (loader.isSpinning())
|
|
599
479
|
loader.succeed(`${AiSession.#chat.model} responded`);
|
|
@@ -614,7 +494,6 @@ class AiSession {
|
|
|
614
494
|
fullResponse += content;
|
|
615
495
|
onChunk(content);
|
|
616
496
|
}
|
|
617
|
-
tokenIdx++;
|
|
618
497
|
}
|
|
619
498
|
fullResponse += `
|
|
620
499
|
`;
|
|
@@ -622,19 +501,33 @@ class AiSession {
|
|
|
622
501
|
`);
|
|
623
502
|
this.messageHistory.push(new AIMessage(fullResponse));
|
|
624
503
|
return { content: fullResponse, messageHistory: this.messageHistory };
|
|
625
|
-
} catch
|
|
504
|
+
} catch {
|
|
626
505
|
loader.fail(`${AiSession.#chat.model} failed to respond`);
|
|
627
506
|
throw new Error("Failed to stream response");
|
|
628
507
|
}
|
|
629
508
|
}
|
|
630
|
-
async edit(question, {
|
|
509
|
+
async edit(question, {
|
|
510
|
+
onChunk,
|
|
511
|
+
onReasoning,
|
|
512
|
+
maxTry = MAX_ASK_TRY,
|
|
513
|
+
validate,
|
|
514
|
+
approve,
|
|
515
|
+
fallbackToPreviousTypescript
|
|
516
|
+
} = {}) {
|
|
631
517
|
for (let tryCount = 0;tryCount < maxTry; tryCount++) {
|
|
632
518
|
let response = await this.ask(question, { onChunk, onReasoning });
|
|
633
519
|
if (validate?.length && tryCount === 0) {
|
|
634
520
|
const validateQuestion = `Double check if the response meets the requirements and conditions, and follow the instructions. If not, rewrite it.
|
|
635
521
|
${validate.map((v) => `- ${v}`).join(`
|
|
636
522
|
`)}`;
|
|
637
|
-
|
|
523
|
+
const validateResponse = await this.ask(validateQuestion, {
|
|
524
|
+
onChunk,
|
|
525
|
+
onReasoning
|
|
526
|
+
});
|
|
527
|
+
response = {
|
|
528
|
+
...validateResponse,
|
|
529
|
+
content: fallbackToPreviousTypescript ? preserveTypescriptResponseContent(response.content, validateResponse.content) : validateResponse.content
|
|
530
|
+
};
|
|
638
531
|
}
|
|
639
532
|
const isConfirmed = approve ? true : await select({
|
|
640
533
|
message: "Do you want to edit the response?",
|
|
@@ -667,28 +560,45 @@ ${validate.map((v) => `- ${v}`).join(`
|
|
|
667
560
|
return this;
|
|
668
561
|
}
|
|
669
562
|
async writeTypescripts(question, executor, options = {}) {
|
|
670
|
-
const content = await this.edit(question,
|
|
563
|
+
const content = await this.edit(question, {
|
|
564
|
+
...options,
|
|
565
|
+
fallbackToPreviousTypescript: true
|
|
566
|
+
});
|
|
671
567
|
const writes = this.#getTypescriptCodes(content);
|
|
568
|
+
if (!writes.length)
|
|
569
|
+
throw new Error("No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.");
|
|
672
570
|
for (const write of writes)
|
|
673
571
|
await executor.writeFile(write.filePath, write.content);
|
|
674
572
|
return await this.#tryFixTypescripts(writes, executor, options);
|
|
675
573
|
}
|
|
676
|
-
async#editTypescripts(question, options = {}) {
|
|
677
|
-
const content = await this.edit(question,
|
|
678
|
-
|
|
574
|
+
async#editTypescripts(question, options = {}, fallbackWrites) {
|
|
575
|
+
const content = await this.edit(question, {
|
|
576
|
+
...options,
|
|
577
|
+
fallbackToPreviousTypescript: true
|
|
578
|
+
});
|
|
579
|
+
const writes = this.#getTypescriptCodes(content);
|
|
580
|
+
if (!writes.length && fallbackWrites?.length)
|
|
581
|
+
return fallbackWrites;
|
|
582
|
+
if (!writes.length)
|
|
583
|
+
throw new Error("No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.");
|
|
584
|
+
return writes;
|
|
679
585
|
}
|
|
680
586
|
async#tryFixTypescripts(writes, executor, options = {}) {
|
|
681
587
|
const MAX_EDIT_TRY = 5;
|
|
682
588
|
for (let tryCount = 0;tryCount < MAX_EDIT_TRY; tryCount++) {
|
|
683
|
-
const loader = new Spinner(`Type checking and linting...`, {
|
|
589
|
+
const loader = new Spinner(`Type checking and linting...`, {
|
|
590
|
+
prefix: `\uD83E\uDD16akan-editor`
|
|
591
|
+
}).start();
|
|
684
592
|
const fileChecks = await Promise.all(writes.map(async ({ filePath }) => {
|
|
685
|
-
const
|
|
686
|
-
const
|
|
687
|
-
const
|
|
688
|
-
|
|
593
|
+
const lintResult = await executor.lint(filePath, { fix: true });
|
|
594
|
+
const typeCheckResult = await executor.typeCheckAsync(filePath);
|
|
595
|
+
const hasTypeErrors = typeCheckResult.fileErrors.length > 0;
|
|
596
|
+
const hasLintErrors = lintResult.errors.length > 0;
|
|
597
|
+
const needFix = hasTypeErrors || hasLintErrors;
|
|
598
|
+
return { filePath, typeCheckResult, lintResult, needFix };
|
|
689
599
|
}));
|
|
690
|
-
const
|
|
691
|
-
if (
|
|
600
|
+
const hasAnyFix = fileChecks.some((fileCheck) => fileCheck.needFix);
|
|
601
|
+
if (hasAnyFix) {
|
|
692
602
|
loader.fail("Type checking and linting has some errors, try to fix them");
|
|
693
603
|
fileChecks.forEach((fileCheck) => {
|
|
694
604
|
Logger2.rawLog(`TypeCheck Result
|
|
@@ -704,7 +614,7 @@ ${fileCheck.lintResult.message}`);
|
|
|
704
614
|
...options,
|
|
705
615
|
validate: undefined,
|
|
706
616
|
approve: true
|
|
707
|
-
});
|
|
617
|
+
}, writes);
|
|
708
618
|
for (const write of writes)
|
|
709
619
|
await executor.writeFile(write.filePath, write.content);
|
|
710
620
|
} else {
|
|
@@ -715,21 +625,7 @@ ${fileCheck.lintResult.message}`);
|
|
|
715
625
|
throw new Error("Failed to create scalar");
|
|
716
626
|
}
|
|
717
627
|
#getTypescriptCodes(text) {
|
|
718
|
-
|
|
719
|
-
if (!codes)
|
|
720
|
-
return [];
|
|
721
|
-
const result = codes.map((code) => {
|
|
722
|
-
const content = /```(typescript|tsx)([\s\S]*?)```/.exec(code)?.[2];
|
|
723
|
-
if (!content)
|
|
724
|
-
return null;
|
|
725
|
-
const filePath = /\/\/ File: (.*?)(?:\n|$)/.exec(content)?.[1]?.trim();
|
|
726
|
-
if (!filePath)
|
|
727
|
-
return null;
|
|
728
|
-
const contentWithoutFilepath = content.replace(`// File: ${filePath}
|
|
729
|
-
`, "").trim();
|
|
730
|
-
return { filePath, content: contentWithoutFilepath };
|
|
731
|
-
});
|
|
732
|
-
return result.filter((code) => code !== null);
|
|
628
|
+
return parseTypescriptFileBlocks(text);
|
|
733
629
|
}
|
|
734
630
|
async editMarkdown(request, options = {}) {
|
|
735
631
|
const content = await this.edit(request, options);
|
|
@@ -747,21 +643,26 @@ ${fileCheck.lintResult.message}`);
|
|
|
747
643
|
}
|
|
748
644
|
// pkgs/@akanjs/devkit/akanApp/akanApp.host.ts
|
|
749
645
|
import path9 from "path";
|
|
750
|
-
import { Logger as
|
|
646
|
+
import { Logger as Logger5 } from "akanjs/common";
|
|
751
647
|
|
|
752
648
|
// pkgs/@akanjs/devkit/executors.ts
|
|
753
649
|
import {
|
|
754
650
|
exec,
|
|
755
651
|
fork,
|
|
756
|
-
spawn
|
|
652
|
+
spawn as spawn2
|
|
757
653
|
} from "child_process";
|
|
758
654
|
import { readFileSync as readFileSync3 } from "fs";
|
|
759
|
-
import {
|
|
655
|
+
import {
|
|
656
|
+
copyFile,
|
|
657
|
+
mkdir as mkdir2,
|
|
658
|
+
readdir as readDirEntries,
|
|
659
|
+
stat as stat2
|
|
660
|
+
} from "fs/promises";
|
|
760
661
|
import path7 from "path";
|
|
761
662
|
import {
|
|
762
663
|
capitalize,
|
|
763
664
|
isRouteSourceFile,
|
|
764
|
-
Logger as
|
|
665
|
+
Logger as Logger3,
|
|
765
666
|
parseRouteModuleKey,
|
|
766
667
|
validatePageSourceFile,
|
|
767
668
|
validateSubRoutePageKey
|
|
@@ -1124,23 +1025,146 @@ import path2 from "path";
|
|
|
1124
1025
|
var getDirname = (url) => path2.dirname(new URL(url).pathname);
|
|
1125
1026
|
|
|
1126
1027
|
// pkgs/@akanjs/devkit/linter.ts
|
|
1028
|
+
import { spawn } from "child_process";
|
|
1127
1029
|
import { existsSync, readFileSync } from "fs";
|
|
1128
|
-
import
|
|
1129
|
-
import { Logger as Logger3 } from "akanjs/common";
|
|
1030
|
+
import path3 from "path";
|
|
1130
1031
|
import chalk2 from "chalk";
|
|
1131
1032
|
|
|
1132
1033
|
class Linter {
|
|
1133
|
-
#logger = new Logger3("Linter");
|
|
1134
1034
|
lintRoot;
|
|
1035
|
+
#biomeBin;
|
|
1135
1036
|
constructor(cwdPath) {
|
|
1136
|
-
this.lintRoot = this.#
|
|
1037
|
+
this.lintRoot = this.#findBiomeRootPath(cwdPath);
|
|
1038
|
+
const localBiomeBin = path3.join(this.lintRoot, "node_modules/.bin/biome");
|
|
1039
|
+
this.#biomeBin = existsSync(localBiomeBin) ? localBiomeBin : "biome";
|
|
1137
1040
|
}
|
|
1138
|
-
#
|
|
1139
|
-
const configPath2 = path3.join(dir, "
|
|
1041
|
+
#findBiomeRootPath(dir) {
|
|
1042
|
+
const configPath2 = path3.join(dir, "biome.json");
|
|
1140
1043
|
if (existsSync(configPath2))
|
|
1141
1044
|
return dir;
|
|
1142
1045
|
const parentDir = path3.dirname(dir);
|
|
1143
|
-
|
|
1046
|
+
if (parentDir === dir)
|
|
1047
|
+
throw new Error(`biome.json not found from ${dir}`);
|
|
1048
|
+
return this.#findBiomeRootPath(parentDir);
|
|
1049
|
+
}
|
|
1050
|
+
#toBiomePath(filePath) {
|
|
1051
|
+
const relativePath = path3.relative(this.lintRoot, filePath);
|
|
1052
|
+
if (!relativePath.startsWith("..") && !path3.isAbsolute(relativePath))
|
|
1053
|
+
return relativePath;
|
|
1054
|
+
return filePath;
|
|
1055
|
+
}
|
|
1056
|
+
#resolveFilePath(filePath) {
|
|
1057
|
+
return path3.isAbsolute(filePath) ? filePath : path3.join(this.lintRoot, filePath);
|
|
1058
|
+
}
|
|
1059
|
+
async#runBiome(args, input2) {
|
|
1060
|
+
return await new Promise((resolve, reject) => {
|
|
1061
|
+
const proc = spawn(this.#biomeBin, args, {
|
|
1062
|
+
cwd: this.lintRoot,
|
|
1063
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1064
|
+
});
|
|
1065
|
+
let stdout = "";
|
|
1066
|
+
let stderr = "";
|
|
1067
|
+
proc.stdout.on("data", (data) => {
|
|
1068
|
+
stdout += data.toString();
|
|
1069
|
+
});
|
|
1070
|
+
proc.stderr.on("data", (data) => {
|
|
1071
|
+
stderr += data.toString();
|
|
1072
|
+
});
|
|
1073
|
+
proc.on("error", reject);
|
|
1074
|
+
proc.on("close", (code) => resolve({ stdout, stderr, code }));
|
|
1075
|
+
proc.stdin.end(input2);
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
#parseBiomeReport(output) {
|
|
1079
|
+
const jsonStart = output.indexOf("{");
|
|
1080
|
+
const jsonEnd = output.lastIndexOf("}");
|
|
1081
|
+
if (jsonStart === -1 || jsonEnd === -1 || jsonEnd < jsonStart)
|
|
1082
|
+
throw new Error(output.trim() || "No Biome JSON output");
|
|
1083
|
+
return JSON.parse(output.slice(jsonStart, jsonEnd + 1));
|
|
1084
|
+
}
|
|
1085
|
+
#diagnosticFilePath(diagnostic, fallbackFilePath) {
|
|
1086
|
+
const diagnosticPath = diagnostic.location?.path;
|
|
1087
|
+
if (!diagnosticPath)
|
|
1088
|
+
return fallbackFilePath;
|
|
1089
|
+
return path3.isAbsolute(diagnosticPath) ? diagnosticPath : path3.join(this.lintRoot, diagnosticPath);
|
|
1090
|
+
}
|
|
1091
|
+
#createLintMessage(diagnostic) {
|
|
1092
|
+
const start = diagnostic.location?.start;
|
|
1093
|
+
const end = diagnostic.location?.end;
|
|
1094
|
+
return {
|
|
1095
|
+
line: Math.max(1, start?.line ?? 1),
|
|
1096
|
+
column: Math.max(1, start?.column ?? 1),
|
|
1097
|
+
endLine: end?.line,
|
|
1098
|
+
endColumn: end?.column,
|
|
1099
|
+
message: diagnostic.message,
|
|
1100
|
+
ruleId: diagnostic.category ?? null,
|
|
1101
|
+
severity: diagnostic.severity === "error" ? 2 : 1
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
#toLintResults(report, filePath) {
|
|
1105
|
+
const resultsByPath = new Map;
|
|
1106
|
+
for (const diagnostic of report.diagnostics ?? []) {
|
|
1107
|
+
if (diagnostic.severity !== "error" && diagnostic.severity !== "warning")
|
|
1108
|
+
continue;
|
|
1109
|
+
const diagnosticFilePath = this.#diagnosticFilePath(diagnostic, filePath);
|
|
1110
|
+
const result = resultsByPath.get(diagnosticFilePath) ?? {
|
|
1111
|
+
filePath: diagnosticFilePath,
|
|
1112
|
+
messages: [],
|
|
1113
|
+
errorCount: 0,
|
|
1114
|
+
warningCount: 0,
|
|
1115
|
+
fixableErrorCount: 0,
|
|
1116
|
+
fixableWarningCount: 0
|
|
1117
|
+
};
|
|
1118
|
+
const message = this.#createLintMessage(diagnostic);
|
|
1119
|
+
result.messages.push(message);
|
|
1120
|
+
if (message.severity === 2)
|
|
1121
|
+
result.errorCount += 1;
|
|
1122
|
+
else
|
|
1123
|
+
result.warningCount += 1;
|
|
1124
|
+
resultsByPath.set(diagnosticFilePath, result);
|
|
1125
|
+
}
|
|
1126
|
+
return [
|
|
1127
|
+
resultsByPath.get(filePath) ?? {
|
|
1128
|
+
filePath,
|
|
1129
|
+
messages: [],
|
|
1130
|
+
errorCount: 0,
|
|
1131
|
+
warningCount: 0,
|
|
1132
|
+
fixableErrorCount: 0,
|
|
1133
|
+
fixableWarningCount: 0
|
|
1134
|
+
},
|
|
1135
|
+
...[...resultsByPath.entries()].filter(([resultPath]) => resultPath !== filePath).map(([, result]) => result)
|
|
1136
|
+
];
|
|
1137
|
+
}
|
|
1138
|
+
#splitMessages(results) {
|
|
1139
|
+
const messages = results.flatMap((result) => result.messages);
|
|
1140
|
+
return {
|
|
1141
|
+
errors: messages.filter((message) => message.severity === 2),
|
|
1142
|
+
warnings: messages.filter((message) => message.severity === 1)
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
async#checkFile(filePath, { write = false } = {}) {
|
|
1146
|
+
const originalContent = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
|
|
1147
|
+
const { stdout, stderr } = await this.#runBiome([
|
|
1148
|
+
"check",
|
|
1149
|
+
...write ? ["--write"] : [],
|
|
1150
|
+
"--reporter=json",
|
|
1151
|
+
"--max-diagnostics=none",
|
|
1152
|
+
"--no-errors-on-unmatched",
|
|
1153
|
+
"--config-path",
|
|
1154
|
+
path3.join(this.lintRoot, "biome.json"),
|
|
1155
|
+
this.#toBiomePath(filePath)
|
|
1156
|
+
]);
|
|
1157
|
+
const report = this.#parseBiomeReport(stdout || stderr);
|
|
1158
|
+
const results = this.#toLintResults(report, filePath);
|
|
1159
|
+
const { errors, warnings } = this.#splitMessages(results);
|
|
1160
|
+
const output = write && existsSync(filePath) ? readFileSync(filePath, "utf8") : undefined;
|
|
1161
|
+
return {
|
|
1162
|
+
fixed: write && output !== originalContent,
|
|
1163
|
+
output,
|
|
1164
|
+
results,
|
|
1165
|
+
errors,
|
|
1166
|
+
warnings
|
|
1167
|
+
};
|
|
1144
1168
|
}
|
|
1145
1169
|
async lint(filePath, { fix = false, dryRun = false } = {}) {
|
|
1146
1170
|
if (fix)
|
|
@@ -1148,9 +1172,10 @@ class Linter {
|
|
|
1148
1172
|
return await this.lintFile(filePath);
|
|
1149
1173
|
}
|
|
1150
1174
|
async lintFile(filePath) {
|
|
1151
|
-
|
|
1175
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1176
|
+
if (!existsSync(resolvedFilePath))
|
|
1152
1177
|
throw new Error(`File not found: ${filePath}`);
|
|
1153
|
-
return
|
|
1178
|
+
return await this.#checkFile(resolvedFilePath);
|
|
1154
1179
|
}
|
|
1155
1180
|
formatLintResults(results) {
|
|
1156
1181
|
if (results.length === 0)
|
|
@@ -1170,12 +1195,12 @@ ${chalk2.cyan(result.filePath)}`);
|
|
|
1170
1195
|
const sourceContent = readFileSync(result.filePath, "utf8");
|
|
1171
1196
|
sourceLines = sourceContent.split(`
|
|
1172
1197
|
`);
|
|
1173
|
-
} catch
|
|
1198
|
+
} catch {}
|
|
1174
1199
|
}
|
|
1175
1200
|
result.messages.forEach((message) => {
|
|
1176
1201
|
const type = message.severity === 2 ? "error" : "warning";
|
|
1177
1202
|
const typeColor = message.severity === 2 ? chalk2.red : chalk2.yellow;
|
|
1178
|
-
const icon = message.severity === 2 ? "
|
|
1203
|
+
const icon = message.severity === 2 ? "x" : "!";
|
|
1179
1204
|
const ruleInfo = message.ruleId ? chalk2.dim(` (${message.ruleId})`) : "";
|
|
1180
1205
|
output.push(`
|
|
1181
1206
|
${icon} ${typeColor(type)}: ${message.message}${ruleInfo}`);
|
|
@@ -1194,7 +1219,7 @@ ${chalk2.dim(`${lineNumber} |`)} ${sourceLine}`);
|
|
|
1194
1219
|
}
|
|
1195
1220
|
});
|
|
1196
1221
|
if (totalErrors === 0 && totalWarnings === 0)
|
|
1197
|
-
return chalk2.bold("
|
|
1222
|
+
return chalk2.bold("No Biome errors or warnings found");
|
|
1198
1223
|
const errorText = totalErrors > 0 ? chalk2.red(`${totalErrors} error(s)`) : "0 errors";
|
|
1199
1224
|
const warningText = totalWarnings > 0 ? chalk2.yellow(`${totalWarnings} warning(s)`) : "0 warnings";
|
|
1200
1225
|
const summary = [`
|
|
@@ -1209,23 +1234,26 @@ ${errorText}, ${warningText} found`];
|
|
|
1209
1234
|
column: message.column,
|
|
1210
1235
|
message: message.message,
|
|
1211
1236
|
ruleId: message.ruleId,
|
|
1212
|
-
severity: message.severity === 2 ? "error" : "warning"
|
|
1213
|
-
fix: message.fix,
|
|
1214
|
-
suggestions: message.suggestions
|
|
1237
|
+
severity: message.severity === 2 ? "error" : "warning"
|
|
1215
1238
|
})));
|
|
1216
1239
|
const stats = results.reduce((acc, result) => ({
|
|
1217
1240
|
errorCount: acc.errorCount + result.errorCount,
|
|
1218
1241
|
warningCount: acc.warningCount + result.warningCount,
|
|
1219
1242
|
fixableErrorCount: acc.fixableErrorCount + result.fixableErrorCount,
|
|
1220
1243
|
fixableWarningCount: acc.fixableWarningCount + result.fixableWarningCount
|
|
1221
|
-
}), {
|
|
1244
|
+
}), {
|
|
1245
|
+
errorCount: 0,
|
|
1246
|
+
warningCount: 0,
|
|
1247
|
+
fixableErrorCount: 0,
|
|
1248
|
+
fixableWarningCount: 0
|
|
1249
|
+
});
|
|
1222
1250
|
return { results, details, stats };
|
|
1223
1251
|
}
|
|
1224
1252
|
async hasNoLintErrors(filePath) {
|
|
1225
1253
|
try {
|
|
1226
1254
|
const { results } = await this.lintFile(filePath);
|
|
1227
1255
|
return results.every((result) => result.errorCount === 0);
|
|
1228
|
-
} catch
|
|
1256
|
+
} catch {
|
|
1229
1257
|
return false;
|
|
1230
1258
|
}
|
|
1231
1259
|
}
|
|
@@ -1238,12 +1266,28 @@ ${errorText}, ${warningText} found`];
|
|
|
1238
1266
|
return results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
|
|
1239
1267
|
}
|
|
1240
1268
|
async fixFile(filePath, dryRun = false) {
|
|
1241
|
-
|
|
1269
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1270
|
+
if (!existsSync(resolvedFilePath))
|
|
1242
1271
|
throw new Error(`File not found: ${filePath}`);
|
|
1243
|
-
|
|
1272
|
+
if (!dryRun)
|
|
1273
|
+
return await this.#checkFile(resolvedFilePath, { write: true });
|
|
1274
|
+
const source = readFileSync(resolvedFilePath, "utf8");
|
|
1275
|
+
const { stdout } = await this.#runBiome([
|
|
1276
|
+
"check",
|
|
1277
|
+
"--write",
|
|
1278
|
+
"--config-path",
|
|
1279
|
+
path3.join(this.lintRoot, "biome.json"),
|
|
1280
|
+
"--stdin-file-path",
|
|
1281
|
+
this.#toBiomePath(resolvedFilePath)
|
|
1282
|
+
], source);
|
|
1283
|
+
const lintResult = await this.lintFile(resolvedFilePath);
|
|
1284
|
+
return { ...lintResult, fixed: stdout !== source, output: stdout };
|
|
1244
1285
|
}
|
|
1245
1286
|
async getConfigForFile(filePath) {
|
|
1246
|
-
|
|
1287
|
+
const resolvedFilePath = this.#resolveFilePath(filePath);
|
|
1288
|
+
if (!existsSync(resolvedFilePath))
|
|
1289
|
+
throw new Error(`File not found: ${filePath}`);
|
|
1290
|
+
return JSON.parse(readFileSync(path3.join(this.lintRoot, "biome.json"), "utf8"));
|
|
1247
1291
|
}
|
|
1248
1292
|
async getProblematicRules(filePath) {
|
|
1249
1293
|
const { results } = await this.lintFile(filePath);
|
|
@@ -1633,23 +1677,23 @@ async function assertScanConvention(exec, libRoot) {
|
|
|
1633
1677
|
files.filter((filename) => !appRootAllowedFiles.has(filename)).forEach((filename) => {
|
|
1634
1678
|
addViolation(filename, "unsupported app root file");
|
|
1635
1679
|
});
|
|
1636
|
-
dirs.filter((
|
|
1637
|
-
addViolation(
|
|
1680
|
+
dirs.filter((dirname) => !appRootAllowedDirs.has(dirname)).forEach((dirname) => {
|
|
1681
|
+
addViolation(dirname, "unsupported app root folder");
|
|
1638
1682
|
});
|
|
1639
1683
|
}
|
|
1640
1684
|
libRoot.files.filter((filename) => !isAllowedLibRootFile(filename)).forEach((filename) => {
|
|
1641
1685
|
addViolation(path5.join("lib", filename), "unsupported lib root file");
|
|
1642
1686
|
});
|
|
1643
|
-
libRoot.dirs.filter((
|
|
1644
|
-
addViolation(path5.join("lib",
|
|
1687
|
+
libRoot.dirs.filter((dirname) => dirname.startsWith("__") && !internalLibDirs.has(dirname)).forEach((dirname) => {
|
|
1688
|
+
addViolation(path5.join("lib", dirname), "unsupported internal lib folder");
|
|
1645
1689
|
});
|
|
1646
|
-
const databaseDirs = libRoot.dirs.filter((
|
|
1647
|
-
const serviceDirs = libRoot.dirs.filter((
|
|
1690
|
+
const databaseDirs = libRoot.dirs.filter((dirname) => !dirname.startsWith("_"));
|
|
1691
|
+
const serviceDirs = libRoot.dirs.filter((dirname) => dirname.startsWith("_") && !dirname.startsWith("__"));
|
|
1648
1692
|
const scalarDirs = await exec.readdir("lib/__scalar");
|
|
1649
1693
|
await Promise.all([
|
|
1650
|
-
...databaseDirs.map((
|
|
1651
|
-
...serviceDirs.map((
|
|
1652
|
-
...scalarDirs.map((
|
|
1694
|
+
...databaseDirs.map((dirname) => validateModuleFiles(exec, violations, "database", path5.join("lib", dirname))),
|
|
1695
|
+
...serviceDirs.map((dirname) => validateModuleFiles(exec, violations, "service", path5.join("lib", dirname))),
|
|
1696
|
+
...scalarDirs.map((dirname) => validateModuleFiles(exec, violations, "scalar", path5.join("lib/__scalar", dirname)))
|
|
1653
1697
|
]);
|
|
1654
1698
|
if (violations.length > 0) {
|
|
1655
1699
|
throw new Error(`[scan-convention]
|
|
@@ -1659,8 +1703,8 @@ ${violations.sort().map((violation) => `- ${violation}`).join(`
|
|
|
1659
1703
|
}
|
|
1660
1704
|
async function validateModuleFiles(exec, violations, kind, modulePath) {
|
|
1661
1705
|
const { files, dirs } = await exec.getFilesAndDirs(modulePath);
|
|
1662
|
-
dirs.forEach((
|
|
1663
|
-
violations.push(`${getScanPath(exec, path5.join(modulePath,
|
|
1706
|
+
dirs.forEach((dirname) => {
|
|
1707
|
+
violations.push(`${getScanPath(exec, path5.join(modulePath, dirname))}: unsupported module folder`);
|
|
1664
1708
|
});
|
|
1665
1709
|
files.forEach((filename) => {
|
|
1666
1710
|
const filePath = path5.join(modulePath, filename);
|
|
@@ -1759,9 +1803,9 @@ class ScanInfo {
|
|
|
1759
1803
|
files.zone.databases.push(name);
|
|
1760
1804
|
});
|
|
1761
1805
|
}),
|
|
1762
|
-
...serviceDirs.map(async (
|
|
1763
|
-
const name =
|
|
1764
|
-
const filenames = await exec.readdir(path5.join("lib",
|
|
1806
|
+
...serviceDirs.map(async (dirname) => {
|
|
1807
|
+
const name = dirname.slice(1);
|
|
1808
|
+
const filenames = await exec.readdir(path5.join("lib", dirname));
|
|
1765
1809
|
filenames.forEach((filename) => {
|
|
1766
1810
|
if (filename.endsWith(".dictionary.ts"))
|
|
1767
1811
|
files.dictionary.services.push(name);
|
|
@@ -2330,8 +2374,13 @@ class CommandExecutionError extends Error {
|
|
|
2330
2374
|
const displayCommand = formatCommandForDisplay(command, args);
|
|
2331
2375
|
const status = signal ? `signal: ${signal}` : `exit code: ${code ?? "unknown"}`;
|
|
2332
2376
|
const output = (stderr || stdout).trim();
|
|
2333
|
-
super([
|
|
2334
|
-
|
|
2377
|
+
super([
|
|
2378
|
+
`Command failed: ${displayCommand}`,
|
|
2379
|
+
`cwd: ${cwd}`,
|
|
2380
|
+
status,
|
|
2381
|
+
output ? `
|
|
2382
|
+
${output}` : ""
|
|
2383
|
+
].join(`
|
|
2335
2384
|
`), {
|
|
2336
2385
|
cause
|
|
2337
2386
|
});
|
|
@@ -2380,7 +2429,13 @@ var parseEnvFile = (envPath) => {
|
|
|
2380
2429
|
}
|
|
2381
2430
|
return env;
|
|
2382
2431
|
};
|
|
2383
|
-
var PAGE_ROUTE_EXPORTS = new Set([
|
|
2432
|
+
var PAGE_ROUTE_EXPORTS = new Set([
|
|
2433
|
+
"default",
|
|
2434
|
+
"pageConfig",
|
|
2435
|
+
"head",
|
|
2436
|
+
"generateHead",
|
|
2437
|
+
"Loading"
|
|
2438
|
+
]);
|
|
2384
2439
|
var ROOT_LAYOUT_EXPORTS = new Set([
|
|
2385
2440
|
"default",
|
|
2386
2441
|
"head",
|
|
@@ -2393,7 +2448,12 @@ var ROOT_LAYOUT_EXPORTS = new Set([
|
|
|
2393
2448
|
"gaTrackingId",
|
|
2394
2449
|
"Loading"
|
|
2395
2450
|
]);
|
|
2396
|
-
var LAYOUT_ROUTE_EXPORTS = new Set([
|
|
2451
|
+
var LAYOUT_ROUTE_EXPORTS = new Set([
|
|
2452
|
+
"default",
|
|
2453
|
+
"head",
|
|
2454
|
+
"generateHead",
|
|
2455
|
+
"Loading"
|
|
2456
|
+
]);
|
|
2397
2457
|
function validateRouteSourceExports(source, filePath, kind, options = {}) {
|
|
2398
2458
|
const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
|
|
2399
2459
|
const allowed = kind === "page" ? PAGE_ROUTE_EXPORTS : options.rootLayout ? ROOT_LAYOUT_EXPORTS : LAYOUT_ROUTE_EXPORTS;
|
|
@@ -2462,16 +2522,16 @@ class Executor {
|
|
|
2462
2522
|
linter = null;
|
|
2463
2523
|
constructor(name, cwdPath) {
|
|
2464
2524
|
this.name = name;
|
|
2465
|
-
this.logger = new
|
|
2525
|
+
this.logger = new Logger3(name);
|
|
2466
2526
|
this.logs = [];
|
|
2467
2527
|
this.cwdPath = cwdPath;
|
|
2468
2528
|
}
|
|
2469
2529
|
#stdout(data) {
|
|
2470
2530
|
if (Executor.verbose)
|
|
2471
|
-
|
|
2531
|
+
Logger3.raw(chalk4.dim(data.toString()));
|
|
2472
2532
|
}
|
|
2473
2533
|
#stderr(data) {
|
|
2474
|
-
|
|
2534
|
+
Logger3.raw(chalk4.red(data.toString()));
|
|
2475
2535
|
}
|
|
2476
2536
|
exec(command, options = {}) {
|
|
2477
2537
|
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
@@ -2488,11 +2548,26 @@ class Executor {
|
|
|
2488
2548
|
});
|
|
2489
2549
|
return new Promise((resolve, reject) => {
|
|
2490
2550
|
proc.on("error", (error) => {
|
|
2491
|
-
reject(new CommandExecutionError({
|
|
2551
|
+
reject(new CommandExecutionError({
|
|
2552
|
+
command,
|
|
2553
|
+
cwd,
|
|
2554
|
+
code: null,
|
|
2555
|
+
signal: null,
|
|
2556
|
+
stdout,
|
|
2557
|
+
stderr,
|
|
2558
|
+
cause: error
|
|
2559
|
+
}));
|
|
2492
2560
|
});
|
|
2493
2561
|
proc.on("exit", (code, signal) => {
|
|
2494
2562
|
if (!!code || signal)
|
|
2495
|
-
reject(new CommandExecutionError({
|
|
2563
|
+
reject(new CommandExecutionError({
|
|
2564
|
+
command,
|
|
2565
|
+
cwd,
|
|
2566
|
+
code,
|
|
2567
|
+
signal,
|
|
2568
|
+
stdout,
|
|
2569
|
+
stderr
|
|
2570
|
+
}));
|
|
2496
2571
|
else
|
|
2497
2572
|
resolve({ code, signal });
|
|
2498
2573
|
});
|
|
@@ -2500,7 +2575,7 @@ class Executor {
|
|
|
2500
2575
|
}
|
|
2501
2576
|
spawn(command, args = [], options = {}) {
|
|
2502
2577
|
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
2503
|
-
const proc =
|
|
2578
|
+
const proc = spawn2(command, args, {
|
|
2504
2579
|
cwd: this.cwdPath,
|
|
2505
2580
|
...options
|
|
2506
2581
|
});
|
|
@@ -2518,18 +2593,35 @@ class Executor {
|
|
|
2518
2593
|
});
|
|
2519
2594
|
return new Promise((resolve, reject) => {
|
|
2520
2595
|
proc.on("error", (error) => {
|
|
2521
|
-
reject(new CommandExecutionError({
|
|
2596
|
+
reject(new CommandExecutionError({
|
|
2597
|
+
command,
|
|
2598
|
+
args,
|
|
2599
|
+
cwd,
|
|
2600
|
+
code: null,
|
|
2601
|
+
signal: null,
|
|
2602
|
+
stdout,
|
|
2603
|
+
stderr,
|
|
2604
|
+
cause: error
|
|
2605
|
+
}));
|
|
2522
2606
|
});
|
|
2523
2607
|
proc.on("close", (code, signal) => {
|
|
2524
2608
|
if (code !== 0 || signal)
|
|
2525
|
-
reject(new CommandExecutionError({
|
|
2609
|
+
reject(new CommandExecutionError({
|
|
2610
|
+
command,
|
|
2611
|
+
args,
|
|
2612
|
+
cwd,
|
|
2613
|
+
code,
|
|
2614
|
+
signal,
|
|
2615
|
+
stdout,
|
|
2616
|
+
stderr
|
|
2617
|
+
}));
|
|
2526
2618
|
else
|
|
2527
2619
|
resolve(stdout);
|
|
2528
2620
|
});
|
|
2529
2621
|
});
|
|
2530
2622
|
}
|
|
2531
2623
|
spawnSync(command, args = [], options = {}) {
|
|
2532
|
-
const proc =
|
|
2624
|
+
const proc = spawn2(command, args, {
|
|
2533
2625
|
cwd: this.cwdPath,
|
|
2534
2626
|
...options
|
|
2535
2627
|
});
|
|
@@ -2566,7 +2658,15 @@ class Executor {
|
|
|
2566
2658
|
});
|
|
2567
2659
|
proc.on("exit", (code, signal) => {
|
|
2568
2660
|
if (!!code || signal)
|
|
2569
|
-
reject(new CommandExecutionError({
|
|
2661
|
+
reject(new CommandExecutionError({
|
|
2662
|
+
command: modulePath,
|
|
2663
|
+
args,
|
|
2664
|
+
cwd,
|
|
2665
|
+
code,
|
|
2666
|
+
signal,
|
|
2667
|
+
stdout,
|
|
2668
|
+
stderr
|
|
2669
|
+
}));
|
|
2570
2670
|
else
|
|
2571
2671
|
resolve({ code, signal });
|
|
2572
2672
|
});
|
|
@@ -2653,7 +2753,7 @@ class Executor {
|
|
|
2653
2753
|
contentStr = currentContent;
|
|
2654
2754
|
} else {
|
|
2655
2755
|
await FileSys.writeText(writePath, contentStr);
|
|
2656
|
-
if (
|
|
2756
|
+
if (Logger3.isVerbose())
|
|
2657
2757
|
this.logger.rawLog(chalk4.yellow(`File Update: ${filePath}`));
|
|
2658
2758
|
}
|
|
2659
2759
|
} else {
|
|
@@ -2700,7 +2800,11 @@ class Executor {
|
|
|
2700
2800
|
this.logger.debug(msg);
|
|
2701
2801
|
return this;
|
|
2702
2802
|
}
|
|
2703
|
-
spinning(msg, {
|
|
2803
|
+
spinning(msg, {
|
|
2804
|
+
prefix = `${this.emoji}${this.name}`,
|
|
2805
|
+
indent = 0,
|
|
2806
|
+
enableSpin = !Executor.verbose
|
|
2807
|
+
} = {}) {
|
|
2704
2808
|
return new Spinner(msg, { prefix, indent, enableSpin }).start();
|
|
2705
2809
|
}
|
|
2706
2810
|
#tsconfig = null;
|
|
@@ -2713,7 +2817,10 @@ class Executor {
|
|
|
2713
2817
|
const result = {
|
|
2714
2818
|
...extendsTsconfig,
|
|
2715
2819
|
...tsconfig,
|
|
2716
|
-
compilerOptions: {
|
|
2820
|
+
compilerOptions: {
|
|
2821
|
+
...extendsTsconfig.compilerOptions,
|
|
2822
|
+
...tsconfig.compilerOptions
|
|
2823
|
+
}
|
|
2717
2824
|
};
|
|
2718
2825
|
this.#tsconfig = result;
|
|
2719
2826
|
return result;
|
|
@@ -2726,7 +2833,9 @@ class Executor {
|
|
|
2726
2833
|
this.#tsconfig = tsconfig;
|
|
2727
2834
|
}
|
|
2728
2835
|
#packageJson = null;
|
|
2729
|
-
async getPackageJson({
|
|
2836
|
+
async getPackageJson({
|
|
2837
|
+
refresh
|
|
2838
|
+
} = {}) {
|
|
2730
2839
|
if (this.#packageJson && !refresh)
|
|
2731
2840
|
return this.#packageJson;
|
|
2732
2841
|
const packageJson = await this.readJson("package.json");
|
|
@@ -2759,8 +2868,8 @@ class Executor {
|
|
|
2759
2868
|
return null;
|
|
2760
2869
|
const filename = typeof result === "object" ? result.filename : path7.basename(targetPath).replace(".js", ".ts");
|
|
2761
2870
|
const content = typeof result === "object" ? result.content : result;
|
|
2762
|
-
const
|
|
2763
|
-
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${
|
|
2871
|
+
const dirname2 = path7.dirname(targetPath);
|
|
2872
|
+
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), `${dirname2}/${filename}`);
|
|
2764
2873
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2765
2874
|
return this.writeFile(convertedTargetPath, content, { overwrite });
|
|
2766
2875
|
} else if (targetPath.endsWith(".template")) {
|
|
@@ -2768,13 +2877,15 @@ class Executor {
|
|
|
2768
2877
|
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath.slice(0, -9));
|
|
2769
2878
|
const convertedContent = Object.entries(dict).reduce((data, [key, value]) => data.replace(new RegExp(`<%= ${key} %>`, "g"), value), content);
|
|
2770
2879
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2771
|
-
return this.writeFile(convertedTargetPath, convertedContent, {
|
|
2880
|
+
return this.writeFile(convertedTargetPath, convertedContent, {
|
|
2881
|
+
overwrite
|
|
2882
|
+
});
|
|
2772
2883
|
} else if (staticTemplateFileExtensions.has(path7.extname(targetPath).toLowerCase())) {
|
|
2773
2884
|
const convertedTargetPath = Object.entries(dict).reduce((path8, [key, value]) => path8.replace(new RegExp(`__${key}__`, "g"), value), targetPath);
|
|
2774
2885
|
const writePath = this.getPath(convertedTargetPath);
|
|
2775
|
-
const
|
|
2776
|
-
if (!await FileSys.dirExists(
|
|
2777
|
-
await mkdir2(
|
|
2886
|
+
const dirname2 = path7.dirname(writePath);
|
|
2887
|
+
if (!await FileSys.dirExists(dirname2))
|
|
2888
|
+
await mkdir2(dirname2, { recursive: true });
|
|
2778
2889
|
await copyFile(templatePath, writePath);
|
|
2779
2890
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
2780
2891
|
return { filePath: writePath, content: "" };
|
|
@@ -2794,14 +2905,24 @@ class Executor {
|
|
|
2794
2905
|
const prefixTemplatePath = templatePath;
|
|
2795
2906
|
if ((await stat2(prefixTemplatePath)).isFile()) {
|
|
2796
2907
|
const filename = path7.basename(prefixTemplatePath);
|
|
2797
|
-
const fileContent = await this.#applyTemplateFile({
|
|
2908
|
+
const fileContent = await this.#applyTemplateFile({
|
|
2909
|
+
templatePath: prefixTemplatePath,
|
|
2910
|
+
targetPath: path7.join(basePath2, filename),
|
|
2911
|
+
scanInfo,
|
|
2912
|
+
overwrite
|
|
2913
|
+
}, dict, options);
|
|
2798
2914
|
return fileContent ? [fileContent] : [];
|
|
2799
2915
|
} else {
|
|
2800
2916
|
const subdirs = await readDirEntries(templatePath);
|
|
2801
2917
|
const fileContents = (await Promise.all(subdirs.map(async (subdir) => {
|
|
2802
2918
|
const subpath = path7.join(templatePath, subdir);
|
|
2803
2919
|
if ((await stat2(subpath)).isFile()) {
|
|
2804
|
-
const fileContent = await this.#applyTemplateFile({
|
|
2920
|
+
const fileContent = await this.#applyTemplateFile({
|
|
2921
|
+
templatePath: subpath,
|
|
2922
|
+
targetPath: path7.join(basePath2, subdir),
|
|
2923
|
+
scanInfo,
|
|
2924
|
+
overwrite
|
|
2925
|
+
}, dict, options);
|
|
2805
2926
|
return fileContent ? [fileContent] : [];
|
|
2806
2927
|
} else
|
|
2807
2928
|
return await this._applyTemplate({
|
|
@@ -2830,7 +2951,10 @@ class Executor {
|
|
|
2830
2951
|
async applyTemplate(options) {
|
|
2831
2952
|
const dict = {
|
|
2832
2953
|
...options.dict ?? {},
|
|
2833
|
-
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
2954
|
+
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
2955
|
+
capitalize(key),
|
|
2956
|
+
capitalize(value)
|
|
2957
|
+
]))
|
|
2834
2958
|
};
|
|
2835
2959
|
return this._applyTemplate({ ...options, dict });
|
|
2836
2960
|
}
|
|
@@ -2845,6 +2969,48 @@ class Executor {
|
|
|
2845
2969
|
const message = typeChecker.formatDiagnostics(fileDiagnostics);
|
|
2846
2970
|
return { fileDiagnostics, fileErrors, fileWarnings, message };
|
|
2847
2971
|
}
|
|
2972
|
+
async typeCheckAsync(filePath) {
|
|
2973
|
+
const path8 = this.getPath(filePath);
|
|
2974
|
+
const entry = await this.#resolveTypecheckWorkerEntry();
|
|
2975
|
+
const proc = Bun.spawn([process.execPath, entry], {
|
|
2976
|
+
cwd: this.cwdPath,
|
|
2977
|
+
env: {
|
|
2978
|
+
...process.env,
|
|
2979
|
+
AKAN_TYPECHECK_CWD: this.cwdPath,
|
|
2980
|
+
AKAN_TYPECHECK_FILE: path8
|
|
2981
|
+
},
|
|
2982
|
+
stdout: "pipe",
|
|
2983
|
+
stderr: "pipe"
|
|
2984
|
+
});
|
|
2985
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
2986
|
+
new Response(proc.stdout).text(),
|
|
2987
|
+
new Response(proc.stderr).text(),
|
|
2988
|
+
proc.exited
|
|
2989
|
+
]);
|
|
2990
|
+
if (exitCode !== 0)
|
|
2991
|
+
throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
|
|
2992
|
+
const result = JSON.parse(stdout);
|
|
2993
|
+
return {
|
|
2994
|
+
fileDiagnostics: Array.from({ length: result.fileDiagnosticsCount }),
|
|
2995
|
+
fileErrors: Array.from({ length: result.fileErrorsCount }),
|
|
2996
|
+
fileWarnings: Array.from({ length: result.fileWarningsCount }),
|
|
2997
|
+
message: result.message
|
|
2998
|
+
};
|
|
2999
|
+
}
|
|
3000
|
+
async#resolveTypecheckWorkerEntry() {
|
|
3001
|
+
const dirname2 = getDirname(import.meta.url);
|
|
3002
|
+
const candidates = [
|
|
3003
|
+
path7.join(process.cwd(), "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
3004
|
+
path7.join(process.cwd(), "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
3005
|
+
path7.join(dirname2, "typecheck/typecheck.proc.ts"),
|
|
3006
|
+
path7.join(dirname2, "typecheck.proc.js"),
|
|
3007
|
+
path7.join(dirname2, "typecheck.proc.ts")
|
|
3008
|
+
];
|
|
3009
|
+
for (const candidate of candidates)
|
|
3010
|
+
if (await Bun.file(candidate).exists())
|
|
3011
|
+
return candidate;
|
|
3012
|
+
throw new Error(`[devkit] typecheck worker entry not found; looked in: ${candidates.join(", ")}`);
|
|
3013
|
+
}
|
|
2848
3014
|
getLinter() {
|
|
2849
3015
|
this.linter ??= new Linter(this.cwdPath);
|
|
2850
3016
|
return this.linter;
|
|
@@ -2852,7 +3018,10 @@ class Executor {
|
|
|
2852
3018
|
async lint(filePath, { fix = false, dryRun = false } = {}) {
|
|
2853
3019
|
const path8 = this.getPath(filePath);
|
|
2854
3020
|
const linter = this.getLinter();
|
|
2855
|
-
const { results, errors, warnings } = await linter.lint(path8, {
|
|
3021
|
+
const { results, errors, warnings } = await linter.lint(path8, {
|
|
3022
|
+
fix,
|
|
3023
|
+
dryRun
|
|
3024
|
+
});
|
|
2856
3025
|
const message = linter.formatLintResults(results);
|
|
2857
3026
|
return { results, message, errors, warnings };
|
|
2858
3027
|
}
|
|
@@ -2878,6 +3047,7 @@ class WorkspaceExecutor extends Executor {
|
|
|
2878
3047
|
const sourceEnv = envPath ? { ...process.env, ...parseEnvFile(envPath) } : process.env;
|
|
2879
3048
|
const appName = sourceEnv.AKAN_PUBLIC_APP_NAME;
|
|
2880
3049
|
const workspaceRoot = sourceEnv.AKAN_WORKSPACE_ROOT;
|
|
3050
|
+
const workspaceId = sourceEnv.AKAN_WORKSPACE_ID;
|
|
2881
3051
|
const repoName = sourceEnv.AKAN_PUBLIC_REPO_NAME;
|
|
2882
3052
|
if (!repoName)
|
|
2883
3053
|
throw new Error("AKAN_PUBLIC_REPO_NAME is not set");
|
|
@@ -2888,7 +3058,23 @@ class WorkspaceExecutor extends Executor {
|
|
|
2888
3058
|
const env = sourceEnv.AKAN_PUBLIC_ENV ?? "debug";
|
|
2889
3059
|
if (!env)
|
|
2890
3060
|
throw new Error("AKAN_PUBLIC_ENV is not set");
|
|
2891
|
-
return {
|
|
3061
|
+
return {
|
|
3062
|
+
...appName ? { appName } : {},
|
|
3063
|
+
workspaceRoot,
|
|
3064
|
+
repoName,
|
|
3065
|
+
serveDomain,
|
|
3066
|
+
env,
|
|
3067
|
+
portOffset,
|
|
3068
|
+
workspaceId
|
|
3069
|
+
};
|
|
3070
|
+
}
|
|
3071
|
+
getWorkspaceId({
|
|
3072
|
+
allowEmpty
|
|
3073
|
+
} = {}) {
|
|
3074
|
+
const { workspaceId } = WorkspaceExecutor.getBaseDevEnv();
|
|
3075
|
+
if (!workspaceId && !allowEmpty)
|
|
3076
|
+
throw new Error("Workspace ID is not found");
|
|
3077
|
+
return workspaceId;
|
|
2892
3078
|
}
|
|
2893
3079
|
async scan() {
|
|
2894
3080
|
return await WorkspaceInfo.fromExecutor(this);
|
|
@@ -2904,7 +3090,10 @@ class WorkspaceExecutor extends Executor {
|
|
|
2904
3090
|
return await this.#getDirHasFile(`${this.workspaceRoot}/libs`, "akan.config.ts");
|
|
2905
3091
|
}
|
|
2906
3092
|
async getSyss() {
|
|
2907
|
-
const [appNames, libNames] = await Promise.all([
|
|
3093
|
+
const [appNames, libNames] = await Promise.all([
|
|
3094
|
+
this.getApps(),
|
|
3095
|
+
this.getLibs()
|
|
3096
|
+
]);
|
|
2908
3097
|
return [appNames, libNames];
|
|
2909
3098
|
}
|
|
2910
3099
|
async getPkgs() {
|
|
@@ -2913,7 +3102,11 @@ class WorkspaceExecutor extends Executor {
|
|
|
2913
3102
|
return await this.#getDirHasFile(`${this.workspaceRoot}/pkgs`, "package.json");
|
|
2914
3103
|
}
|
|
2915
3104
|
async getExecs() {
|
|
2916
|
-
const [appNames, libNames, pkgNames] = await Promise.all([
|
|
3105
|
+
const [appNames, libNames, pkgNames] = await Promise.all([
|
|
3106
|
+
this.getApps(),
|
|
3107
|
+
this.getLibs(),
|
|
3108
|
+
this.getPkgs()
|
|
3109
|
+
]);
|
|
2917
3110
|
return [appNames, libNames, pkgNames];
|
|
2918
3111
|
}
|
|
2919
3112
|
async setPkgTsPaths(name) {
|
|
@@ -2931,7 +3124,10 @@ class WorkspaceExecutor extends Executor {
|
|
|
2931
3124
|
async unsetPkgTsPaths(name) {
|
|
2932
3125
|
const rootTsConfig = await this.readJson("tsconfig.json");
|
|
2933
3126
|
const filteredKeys = Object.keys(rootTsConfig.compilerOptions.paths ?? {}).filter((key) => key !== name && key !== `${name}/*`);
|
|
2934
|
-
rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [
|
|
3127
|
+
rootTsConfig.compilerOptions.paths = Object.fromEntries(filteredKeys.map((key) => [
|
|
3128
|
+
key,
|
|
3129
|
+
rootTsConfig.compilerOptions.paths?.[key] ?? []
|
|
3130
|
+
]));
|
|
2935
3131
|
if (rootTsConfig.references) {
|
|
2936
3132
|
rootTsConfig.references = rootTsConfig.references.filter((ref) => ref.path !== `./pkgs/${name}/tsconfig.json`);
|
|
2937
3133
|
}
|
|
@@ -2940,12 +3136,12 @@ class WorkspaceExecutor extends Executor {
|
|
|
2940
3136
|
}
|
|
2941
3137
|
async getDirInModule(basePath2, name) {
|
|
2942
3138
|
const AVOID_DIRS = ["__lib", "__scalar", `_`, `_${name}`];
|
|
2943
|
-
const getDirs = async (
|
|
2944
|
-
const dirs = await this.readdir(
|
|
3139
|
+
const getDirs = async (dirname2, maxDepth = 3, results = [], prefix = "") => {
|
|
3140
|
+
const dirs = await this.readdir(dirname2);
|
|
2945
3141
|
await Promise.all(dirs.map(async (dir) => {
|
|
2946
3142
|
if (dir.includes("_") || AVOID_DIRS.includes(dir))
|
|
2947
3143
|
return;
|
|
2948
|
-
const dirPath = path7.join(
|
|
3144
|
+
const dirPath = path7.join(dirname2, dir);
|
|
2949
3145
|
if ((await stat2(dirPath)).isDirectory()) {
|
|
2950
3146
|
results.push(`${prefix}${dir}`);
|
|
2951
3147
|
if (maxDepth > 0)
|
|
@@ -2965,12 +3161,12 @@ class WorkspaceExecutor extends Executor {
|
|
|
2965
3161
|
}
|
|
2966
3162
|
async#getDirHasFile(basePath2, targetFilename) {
|
|
2967
3163
|
const AVOID_DIRS = ["node_modules", "dist", "public", "webkit"];
|
|
2968
|
-
const getDirs = async (
|
|
2969
|
-
const dirs = await this.readdir(
|
|
3164
|
+
const getDirs = async (dirname2, maxDepth = 3, results = [], prefix = "") => {
|
|
3165
|
+
const dirs = await this.readdir(dirname2);
|
|
2970
3166
|
await Promise.all(dirs.map(async (dir) => {
|
|
2971
3167
|
if (AVOID_DIRS.includes(dir))
|
|
2972
3168
|
return;
|
|
2973
|
-
const dirPath = path7.join(
|
|
3169
|
+
const dirPath = path7.join(dirname2, dir);
|
|
2974
3170
|
if ((await stat2(dirPath)).isDirectory()) {
|
|
2975
3171
|
const hasTargetFile = await FileSys.fileExists(path7.join(dirPath, targetFilename));
|
|
2976
3172
|
if (hasTargetFile)
|
|
@@ -3023,7 +3219,11 @@ class SysExecutor extends Executor {
|
|
|
3023
3219
|
name;
|
|
3024
3220
|
type;
|
|
3025
3221
|
emoji;
|
|
3026
|
-
constructor({
|
|
3222
|
+
constructor({
|
|
3223
|
+
workspace = WorkspaceExecutor.fromRoot(),
|
|
3224
|
+
name,
|
|
3225
|
+
type
|
|
3226
|
+
}) {
|
|
3027
3227
|
super(name, `${workspace.workspaceRoot}/${type}s/${name}`);
|
|
3028
3228
|
this.workspace = workspace;
|
|
3029
3229
|
this.name = name;
|
|
@@ -3092,7 +3292,11 @@ class SysExecutor extends Executor {
|
|
|
3092
3292
|
} = {}) {
|
|
3093
3293
|
if (this.#scanInfo && !refresh)
|
|
3094
3294
|
return this.#scanInfo;
|
|
3095
|
-
const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, {
|
|
3295
|
+
const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, {
|
|
3296
|
+
refresh
|
|
3297
|
+
}) : await LibInfo.fromExecutor(this, {
|
|
3298
|
+
refresh
|
|
3299
|
+
});
|
|
3096
3300
|
if (write) {
|
|
3097
3301
|
await Promise.all(this.#getScanTemplateTasks(scanInfo));
|
|
3098
3302
|
await this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
|
|
@@ -3122,7 +3326,10 @@ class SysExecutor extends Executor {
|
|
|
3122
3326
|
},
|
|
3123
3327
|
devDependencies: {
|
|
3124
3328
|
...Object.fromEntries(Object.entries(libPackageJson.devDependencies ?? {}).filter(([dep]) => !dependencySet.has(dep))),
|
|
3125
|
-
...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [
|
|
3329
|
+
...Object.fromEntries(devDependencies.filter((dep) => rootPackageJson.dependencies?.[dep] || rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [
|
|
3330
|
+
dep,
|
|
3331
|
+
rootPackageJson.devDependencies?.[dep] ?? rootPackageJson.dependencies?.[dep]
|
|
3332
|
+
]))
|
|
3126
3333
|
}
|
|
3127
3334
|
};
|
|
3128
3335
|
await this.setPackageJson(libPkgJsonWithDeps);
|
|
@@ -3189,7 +3396,11 @@ class SysExecutor extends Executor {
|
|
|
3189
3396
|
...await LibExecutor.from(this, lib).getConstantFiles(),
|
|
3190
3397
|
...await LibExecutor.from(this, lib).getScalarConstantFiles()
|
|
3191
3398
|
]));
|
|
3192
|
-
return [
|
|
3399
|
+
return [
|
|
3400
|
+
...sysContantFiles,
|
|
3401
|
+
...sysScalarConstantFiles,
|
|
3402
|
+
...libConstantFiles.flat()
|
|
3403
|
+
];
|
|
3193
3404
|
}
|
|
3194
3405
|
async getDictionaryFiles() {
|
|
3195
3406
|
const modules = await this.getModules();
|
|
@@ -3198,10 +3409,17 @@ class SysExecutor extends Executor {
|
|
|
3198
3409
|
async applyTemplate(options) {
|
|
3199
3410
|
const dict = {
|
|
3200
3411
|
...options.dict ?? {},
|
|
3201
|
-
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
3412
|
+
...Object.fromEntries(Object.entries(options.dict ?? {}).map(([key, value]) => [
|
|
3413
|
+
capitalize(key),
|
|
3414
|
+
capitalize(value)
|
|
3415
|
+
]))
|
|
3202
3416
|
};
|
|
3203
3417
|
const scanInfo = await this.scan();
|
|
3204
|
-
const fileContents = await this._applyTemplate({
|
|
3418
|
+
const fileContents = await this._applyTemplate({
|
|
3419
|
+
...options,
|
|
3420
|
+
scanInfo,
|
|
3421
|
+
dict
|
|
3422
|
+
});
|
|
3205
3423
|
await this.scan();
|
|
3206
3424
|
return fileContents;
|
|
3207
3425
|
}
|
|
@@ -3253,7 +3471,10 @@ class AppExecutor extends SysExecutor {
|
|
|
3253
3471
|
if (type === "build") {
|
|
3254
3472
|
if (await this.exists(this.dist.cwdPath))
|
|
3255
3473
|
await this.dist.exec(`rm -rf ${this.dist.cwdPath}`);
|
|
3256
|
-
await Promise.all([
|
|
3474
|
+
await Promise.all([
|
|
3475
|
+
this.dist.mkdir("private"),
|
|
3476
|
+
this.dist.mkdir("public")
|
|
3477
|
+
]);
|
|
3257
3478
|
await Promise.all([
|
|
3258
3479
|
this.cp("private", `${this.dist.cwdPath}/private`),
|
|
3259
3480
|
this.cp("public", `${this.dist.cwdPath}/public`)
|
|
@@ -3296,7 +3517,9 @@ class AppExecutor extends SysExecutor {
|
|
|
3296
3517
|
return this.#akanConfig;
|
|
3297
3518
|
}
|
|
3298
3519
|
#pageKeys = null;
|
|
3299
|
-
async getPageKeys({
|
|
3520
|
+
async getPageKeys({
|
|
3521
|
+
refresh
|
|
3522
|
+
} = {}) {
|
|
3300
3523
|
if (this.#pageKeys && !refresh)
|
|
3301
3524
|
return this.#pageKeys;
|
|
3302
3525
|
const akanConfig2 = await this.getConfig();
|
|
@@ -3307,7 +3530,11 @@ class AppExecutor extends SysExecutor {
|
|
|
3307
3530
|
this.#pageKeys = [];
|
|
3308
3531
|
return this.#pageKeys;
|
|
3309
3532
|
}
|
|
3310
|
-
for await (const rel of glob.scan({
|
|
3533
|
+
for await (const rel of glob.scan({
|
|
3534
|
+
cwd: pageDir,
|
|
3535
|
+
absolute: false,
|
|
3536
|
+
onlyFiles: true
|
|
3537
|
+
})) {
|
|
3311
3538
|
const segments = rel.split(path7.sep);
|
|
3312
3539
|
if (segments.some((s) => s === "node_modules"))
|
|
3313
3540
|
continue;
|
|
@@ -3317,7 +3544,10 @@ class AppExecutor extends SysExecutor {
|
|
|
3317
3544
|
if (!isRouteSourceFile(posix))
|
|
3318
3545
|
continue;
|
|
3319
3546
|
const key = `./${posix}`;
|
|
3320
|
-
validateSubRoutePageKey(key, akanConfig2.basePaths, {
|
|
3547
|
+
validateSubRoutePageKey(key, akanConfig2.basePaths, {
|
|
3548
|
+
appName: this.name,
|
|
3549
|
+
filePath: absPath
|
|
3550
|
+
});
|
|
3321
3551
|
const parsed = parseRouteModuleKey(key);
|
|
3322
3552
|
if (parsed.isInternalRootLayout) {
|
|
3323
3553
|
throw new Error(`[route-convention] __root_layout is reserved for Akan.js generated root layout: ${absPath}`);
|
|
@@ -3338,7 +3568,10 @@ class AppExecutor extends SysExecutor {
|
|
|
3338
3568
|
const projectAssetsPath = `${this.cwdPath}/private`;
|
|
3339
3569
|
const projectPublicLibPath = `${projectPublicPath}/libs`;
|
|
3340
3570
|
const projectAssetsLibPath = `${projectAssetsPath}/libs`;
|
|
3341
|
-
await Promise.all([
|
|
3571
|
+
await Promise.all([
|
|
3572
|
+
this.removeDir(projectPublicLibPath),
|
|
3573
|
+
this.removeDir(projectAssetsLibPath)
|
|
3574
|
+
]);
|
|
3342
3575
|
const targetPublicDeps = [];
|
|
3343
3576
|
for (const dep of libDeps) {
|
|
3344
3577
|
if (await this.exists(`${this.workspace.workspaceRoot}/libs/${dep}/public`))
|
|
@@ -3356,8 +3589,15 @@ class AppExecutor extends SysExecutor {
|
|
|
3356
3589
|
...targetAssetsDeps.map((dep) => this.cp(`${this.workspace.workspaceRoot}/libs/${dep}/private`, `${projectAssetsLibPath}/${dep}`))
|
|
3357
3590
|
]);
|
|
3358
3591
|
}
|
|
3359
|
-
async scanSync({
|
|
3360
|
-
|
|
3592
|
+
async scanSync({
|
|
3593
|
+
refresh = false,
|
|
3594
|
+
write = true
|
|
3595
|
+
} = {}) {
|
|
3596
|
+
const scanInfo = await this.scan({
|
|
3597
|
+
refresh,
|
|
3598
|
+
write,
|
|
3599
|
+
writeLib: write
|
|
3600
|
+
});
|
|
3361
3601
|
if (write)
|
|
3362
3602
|
await this.syncAssets(scanInfo.getScanResult().libDeps);
|
|
3363
3603
|
return scanInfo;
|
|
@@ -3401,7 +3641,10 @@ class PkgExecutor extends Executor {
|
|
|
3401
3641
|
name;
|
|
3402
3642
|
dist;
|
|
3403
3643
|
emoji = execEmoji.pkg;
|
|
3404
|
-
constructor({
|
|
3644
|
+
constructor({
|
|
3645
|
+
workspace = WorkspaceExecutor.fromRoot(),
|
|
3646
|
+
name
|
|
3647
|
+
}) {
|
|
3405
3648
|
super(name, `${workspace.workspaceRoot}/pkgs/${name}`);
|
|
3406
3649
|
this.workspace = workspace;
|
|
3407
3650
|
this.name = name;
|
|
@@ -3421,7 +3664,10 @@ class PkgExecutor extends Executor {
|
|
|
3421
3664
|
return scanInfo;
|
|
3422
3665
|
}
|
|
3423
3666
|
async#getDependencyVersion(rootPackageJson, dep) {
|
|
3424
|
-
const rootDeps = {
|
|
3667
|
+
const rootDeps = {
|
|
3668
|
+
...rootPackageJson.dependencies,
|
|
3669
|
+
...rootPackageJson.devDependencies
|
|
3670
|
+
};
|
|
3425
3671
|
const rootVersion = rootDeps[dep];
|
|
3426
3672
|
if (rootVersion)
|
|
3427
3673
|
return rootVersion;
|
|
@@ -3462,7 +3708,10 @@ class PkgExecutor extends Executor {
|
|
|
3462
3708
|
};
|
|
3463
3709
|
}
|
|
3464
3710
|
async updatePackageJsonDependencies(dependencies = [], devDependencies = []) {
|
|
3465
|
-
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3711
|
+
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3712
|
+
this.workspace.getPackageJson(),
|
|
3713
|
+
this.getPackageJson()
|
|
3714
|
+
]);
|
|
3466
3715
|
const dependencyMaps = await this.#toDependencyMap(rootPackageJson, dependencies, devDependencies);
|
|
3467
3716
|
const newPkgJson = {
|
|
3468
3717
|
...pkgJson,
|
|
@@ -3472,16 +3721,29 @@ class PkgExecutor extends Executor {
|
|
|
3472
3721
|
return newPkgJson;
|
|
3473
3722
|
}
|
|
3474
3723
|
async generateDistPackageJson(dependencies = [], devDependencies = []) {
|
|
3475
|
-
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3724
|
+
const [rootPackageJson, pkgJson] = await Promise.all([
|
|
3725
|
+
this.workspace.getPackageJson(),
|
|
3726
|
+
this.getPackageJson()
|
|
3727
|
+
]);
|
|
3476
3728
|
const dependencyMaps = await this.#toDependencyMap(rootPackageJson, dependencies, devDependencies);
|
|
3477
3729
|
const distPkgJson = {
|
|
3478
3730
|
...pkgJson,
|
|
3479
3731
|
type: "module",
|
|
3480
|
-
exports: {
|
|
3732
|
+
exports: {
|
|
3733
|
+
...pkgJson.exports,
|
|
3734
|
+
".": {
|
|
3735
|
+
import: "./index.ts",
|
|
3736
|
+
types: "./index.ts",
|
|
3737
|
+
default: "./index.ts"
|
|
3738
|
+
}
|
|
3739
|
+
},
|
|
3481
3740
|
engines: { bun: ">=1.3.13" },
|
|
3482
3741
|
...dependencyMaps
|
|
3483
3742
|
};
|
|
3484
|
-
await Promise.all([
|
|
3743
|
+
await Promise.all([
|
|
3744
|
+
this.dist.writeJson("package.json", distPkgJson),
|
|
3745
|
+
this.writeJson("package.json", distPkgJson)
|
|
3746
|
+
]);
|
|
3485
3747
|
return distPkgJson;
|
|
3486
3748
|
}
|
|
3487
3749
|
async build() {
|
|
@@ -3494,7 +3756,10 @@ class PkgExecutor extends Executor {
|
|
|
3494
3756
|
await this.cp(`${this.cwdPath}/dist`, this.dist.cwdPath);
|
|
3495
3757
|
}
|
|
3496
3758
|
async generateTsconfigJson() {
|
|
3497
|
-
const [rootTsconfig, pkgTsconfig] = await Promise.all([
|
|
3759
|
+
const [rootTsconfig, pkgTsconfig] = await Promise.all([
|
|
3760
|
+
this.workspace.getTsConfig(),
|
|
3761
|
+
this.getTsConfig()
|
|
3762
|
+
]);
|
|
3498
3763
|
const tsconfig = {
|
|
3499
3764
|
...rootTsconfig,
|
|
3500
3765
|
...pkgTsconfig,
|
|
@@ -3658,7 +3923,7 @@ var createTunnel = async (service, { app, environment, port = service === "postg
|
|
|
3658
3923
|
|
|
3659
3924
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.host.ts
|
|
3660
3925
|
import path8 from "path";
|
|
3661
|
-
import { Logger as
|
|
3926
|
+
import { Logger as Logger4 } from "akanjs/common";
|
|
3662
3927
|
var builderMsgTypeSet = new Set([
|
|
3663
3928
|
"build-route-res",
|
|
3664
3929
|
"builder-ready",
|
|
@@ -3670,7 +3935,7 @@ var builderMsgTypeSet = new Set([
|
|
|
3670
3935
|
class IncrementalBuilderHost {
|
|
3671
3936
|
static #restartBaseDelayMs = 1000;
|
|
3672
3937
|
static #restartMaxDelayMs = 30000;
|
|
3673
|
-
logger = new
|
|
3938
|
+
logger = new Logger4("IncrementalBuilderHost");
|
|
3674
3939
|
entry;
|
|
3675
3940
|
env;
|
|
3676
3941
|
app;
|
|
@@ -3918,7 +4183,7 @@ class BackendImportGraph {
|
|
|
3918
4183
|
|
|
3919
4184
|
class AkanAppHost {
|
|
3920
4185
|
app;
|
|
3921
|
-
logger = new
|
|
4186
|
+
logger = new Logger5("AkanAppHost");
|
|
3922
4187
|
withInk;
|
|
3923
4188
|
env;
|
|
3924
4189
|
#backend = null;
|
|
@@ -4201,19 +4466,19 @@ class AkanAppHost {
|
|
|
4201
4466
|
}
|
|
4202
4467
|
}
|
|
4203
4468
|
// pkgs/@akanjs/devkit/applicationBuildReporter.ts
|
|
4204
|
-
import { Logger as
|
|
4469
|
+
import { Logger as Logger6 } from "akanjs/common";
|
|
4205
4470
|
|
|
4206
4471
|
class ApplicationBuildReporter {
|
|
4207
4472
|
static create() {
|
|
4208
4473
|
return {
|
|
4209
|
-
phaseDone: (phase) =>
|
|
4474
|
+
phaseDone: (phase) => Logger6.rawLog(ApplicationBuildReporter.formatPhaseLine(phase))
|
|
4210
4475
|
};
|
|
4211
4476
|
}
|
|
4212
4477
|
static printSummary(result) {
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4478
|
+
Logger6.rawLog("");
|
|
4479
|
+
Logger6.rawLog(`Route artifacts: ${result.artifactDir}`);
|
|
4480
|
+
Logger6.rawLog(`Server output: ${result.outputDir}`);
|
|
4481
|
+
Logger6.rawLog(`Done in ${ApplicationBuildReporter.formatDuration(result.durationMs)}`);
|
|
4217
4482
|
}
|
|
4218
4483
|
static formatError(error) {
|
|
4219
4484
|
if (error instanceof AggregateError) {
|
|
@@ -4512,13 +4777,13 @@ import path14 from "path";
|
|
|
4512
4777
|
|
|
4513
4778
|
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
4514
4779
|
import path12 from "path";
|
|
4515
|
-
import { Logger as
|
|
4780
|
+
import { Logger as Logger7 } from "akanjs/common";
|
|
4516
4781
|
var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
|
|
4517
4782
|
var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
|
|
4518
4783
|
var CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
4519
4784
|
|
|
4520
4785
|
class BarrelAnalyzer {
|
|
4521
|
-
#logger = new
|
|
4786
|
+
#logger = new Logger7("BarrelAnalyzer");
|
|
4522
4787
|
#opts;
|
|
4523
4788
|
#cache = new Map;
|
|
4524
4789
|
#tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
@@ -6218,7 +6483,7 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
6218
6483
|
}
|
|
6219
6484
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
6220
6485
|
import path23 from "path";
|
|
6221
|
-
import { Logger as
|
|
6486
|
+
import { Logger as Logger8 } from "akanjs/common";
|
|
6222
6487
|
import { compile } from "tailwindcss";
|
|
6223
6488
|
|
|
6224
6489
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
@@ -6363,7 +6628,7 @@ var NODE_MODULES_RE3 = /[\\/]node_modules[\\/]/;
|
|
|
6363
6628
|
var AKANJS_NODE_MODULE_RE3 = /[\\/]node_modules[\\/]akanjs[\\/]/;
|
|
6364
6629
|
|
|
6365
6630
|
class CssCompiler {
|
|
6366
|
-
#logger = new
|
|
6631
|
+
#logger = new Logger8("CssCompiler");
|
|
6367
6632
|
#transpiler = new Bun.Transpiler({ loader: "tsx" });
|
|
6368
6633
|
#app;
|
|
6369
6634
|
#cssImportResolver = null;
|
|
@@ -7771,7 +8036,7 @@ class ApplicationBuildRunner {
|
|
|
7771
8036
|
import { cp, mkdir as mkdir8, rm as rm3 } from "fs/promises";
|
|
7772
8037
|
|
|
7773
8038
|
// pkgs/@akanjs/devkit/uploadRelease.ts
|
|
7774
|
-
import { HttpClient, Logger as
|
|
8039
|
+
import { HttpClient as HttpClient2, Logger as Logger9 } from "akanjs/common";
|
|
7775
8040
|
var spinning = (message) => {
|
|
7776
8041
|
const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
|
|
7777
8042
|
return spinner;
|
|
@@ -7784,9 +8049,9 @@ var uploadRelease = async (appName, {
|
|
|
7784
8049
|
os,
|
|
7785
8050
|
local
|
|
7786
8051
|
}) => {
|
|
7787
|
-
const logger = new
|
|
8052
|
+
const logger = new Logger9("uploadRelease");
|
|
7788
8053
|
const basePath2 = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
|
|
7789
|
-
const httpClient = new
|
|
8054
|
+
const httpClient = new HttpClient2(basePath2);
|
|
7790
8055
|
const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
|
|
7791
8056
|
const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
|
|
7792
8057
|
const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
|
|
@@ -8770,7 +9035,7 @@ var Workspace = createInternalArgToken("Workspace");
|
|
|
8770
9035
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
8771
9036
|
import path36 from "path";
|
|
8772
9037
|
import { confirm, input as input2, select as select2 } from "@inquirer/prompts";
|
|
8773
|
-
import { Logger as
|
|
9038
|
+
import { Logger as Logger10 } from "akanjs/common";
|
|
8774
9039
|
import chalk6 from "chalk";
|
|
8775
9040
|
import { program } from "commander";
|
|
8776
9041
|
|
|
@@ -9055,7 +9320,7 @@ var printCliError = (error) => {
|
|
|
9055
9320
|
if (loggedCliErrorMessages.has(message))
|
|
9056
9321
|
return;
|
|
9057
9322
|
loggedCliErrorMessages.add(message);
|
|
9058
|
-
|
|
9323
|
+
Logger10.rawLog(`
|
|
9059
9324
|
${chalk6.red(message)}`);
|
|
9060
9325
|
};
|
|
9061
9326
|
var handleOption = (programCommand, argMeta) => {
|
|
@@ -9284,7 +9549,7 @@ var runCommands = async (...commands) => {
|
|
|
9284
9549
|
const hasCommand = process.argv.length > 2 && !process.argv[2]?.startsWith("-");
|
|
9285
9550
|
if (hasHelpFlag || !hasCommand) {
|
|
9286
9551
|
if (process.argv.length === 2 || process.argv.length === 3 && hasHelpFlag) {
|
|
9287
|
-
|
|
9552
|
+
Logger10.rawLog(formatHelp(commands, process.env.AKAN_VERSION));
|
|
9288
9553
|
process.exit(0);
|
|
9289
9554
|
}
|
|
9290
9555
|
}
|
|
@@ -9293,7 +9558,7 @@ var runCommands = async (...commands) => {
|
|
|
9293
9558
|
});
|
|
9294
9559
|
const installedAkanPackageJson = await FileSys.fileExists("./node_modules/akanjs/package.json") ? await FileSys.readJson("./node_modules/akanjs/package.json") : null;
|
|
9295
9560
|
if (installedAkanPackageJson && installedAkanPackageJson.version !== process.env.AKAN_VERSION) {
|
|
9296
|
-
|
|
9561
|
+
Logger10.rawLog(chalk6.yellow(`
|
|
9297
9562
|
Akan CLI version is mismatch with installed package. ${process.env.AKAN_VERSION} (global) vs ${installedAkanPackageJson.version} (akanjs)
|
|
9298
9563
|
It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`));
|
|
9299
9564
|
}
|
|
@@ -9329,7 +9594,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
|
|
|
9329
9594
|
return formatCommandHelp(command, targetMeta.key);
|
|
9330
9595
|
};
|
|
9331
9596
|
programCommand.action(async (...args) => {
|
|
9332
|
-
|
|
9597
|
+
Logger10.rawLog();
|
|
9333
9598
|
const cmdArgs = args.slice(0, args.length - 2);
|
|
9334
9599
|
const opt = args[args.length - 2];
|
|
9335
9600
|
const commandArgs = [];
|
|
@@ -9353,7 +9618,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`)
|
|
|
9353
9618
|
const cmd = CommandContainer.get(command);
|
|
9354
9619
|
try {
|
|
9355
9620
|
await targetMeta.handler.call(cmd, ...commandArgs);
|
|
9356
|
-
|
|
9621
|
+
Logger10.rawLog();
|
|
9357
9622
|
} catch (e) {
|
|
9358
9623
|
printCliError(e);
|
|
9359
9624
|
throw e;
|
|
@@ -9693,8 +9958,11 @@ import fsPromise from "fs/promises";
|
|
|
9693
9958
|
import { input as input3, select as select3 } from "@inquirer/prompts";
|
|
9694
9959
|
class Prompter {
|
|
9695
9960
|
static async#getGuidelineRoot() {
|
|
9696
|
-
const
|
|
9697
|
-
const candidates = [
|
|
9961
|
+
const dirname2 = getDirname(import.meta.url);
|
|
9962
|
+
const candidates = [
|
|
9963
|
+
`${dirname2}/guidelines`,
|
|
9964
|
+
`${dirname2}/../cli/guidelines`
|
|
9965
|
+
];
|
|
9698
9966
|
for (const candidate of candidates) {
|
|
9699
9967
|
try {
|
|
9700
9968
|
await fsPromise.access(candidate);
|
|
@@ -9706,7 +9974,10 @@ class Prompter {
|
|
|
9706
9974
|
static async selectGuideline() {
|
|
9707
9975
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
9708
9976
|
const guideNames = (await fsPromise.readdir(guidelineRoot)).filter((name) => !name.startsWith("_"));
|
|
9709
|
-
return await select3({
|
|
9977
|
+
return await select3({
|
|
9978
|
+
message: "Select a guideline",
|
|
9979
|
+
choices: guideNames.map((name) => ({ name, value: name }))
|
|
9980
|
+
});
|
|
9710
9981
|
}
|
|
9711
9982
|
static async getGuideJson(guideName) {
|
|
9712
9983
|
const guidelineRoot = await Prompter.#getGuidelineRoot();
|
|
@@ -9721,13 +9992,18 @@ class Prompter {
|
|
|
9721
9992
|
return content;
|
|
9722
9993
|
}
|
|
9723
9994
|
static async getUpdateRequest(guideName) {
|
|
9724
|
-
return await input3({
|
|
9995
|
+
return await input3({
|
|
9996
|
+
message: `What do you want to update in ${guideName}?`
|
|
9997
|
+
});
|
|
9725
9998
|
}
|
|
9726
9999
|
async makeTsFileUpdatePrompt({ context, request }) {
|
|
9727
10000
|
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:
|
|
9728
10001
|
${await this.getDocumentation("framework")}
|
|
9729
10002
|
Please understand the following background information, write code that meets the requirements, verify that it satisfies the validation conditions, and return the result.
|
|
9730
10003
|
|
|
10004
|
+
# Code Style
|
|
10005
|
+
- Use double quotes for all string literals in TypeScript/TSX code. Do not use single quotes.
|
|
10006
|
+
|
|
9731
10007
|
# Background Information
|
|
9732
10008
|
\`\`\`markdown
|
|
9733
10009
|
${context}
|
|
@@ -9773,82 +10049,11 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
|
|
|
9773
10049
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
9774
10050
|
import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
9775
10051
|
"use client";
|
|
9776
|
-
// pkgs/@akanjs/devkit/cloud/cloudApi.ts
|
|
9777
|
-
var import_dayjs = __toESM(require_dayjs_min(), 1);
|
|
9778
|
-
|
|
9779
|
-
class HttpClient2 {
|
|
9780
|
-
baseUrl;
|
|
9781
|
-
constructor(baseUrl) {
|
|
9782
|
-
this.baseUrl = baseUrl;
|
|
9783
|
-
}
|
|
9784
|
-
async get(url, { headers } = {}) {
|
|
9785
|
-
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
9786
|
-
headers: { "Content-Type": "application/json", ...headers }
|
|
9787
|
-
});
|
|
9788
|
-
return response.json();
|
|
9789
|
-
}
|
|
9790
|
-
async post(url, data, { headers } = {}) {
|
|
9791
|
-
const isFormData = data instanceof FormData;
|
|
9792
|
-
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
9793
|
-
method: "POST",
|
|
9794
|
-
body: isFormData ? data : JSON.stringify(data),
|
|
9795
|
-
headers: isFormData ? headers : { "Content-Type": "application/json", ...headers }
|
|
9796
|
-
});
|
|
9797
|
-
return response.json();
|
|
9798
|
-
}
|
|
9799
|
-
}
|
|
9800
|
-
|
|
9801
|
-
class CloudApi {
|
|
9802
|
-
api;
|
|
9803
|
-
#accessToken = null;
|
|
9804
|
-
constructor(host, { accessToken } = {}) {
|
|
9805
|
-
this.api = new HttpClient2(`${host}/api`);
|
|
9806
|
-
this.#accessToken = accessToken ?? null;
|
|
9807
|
-
}
|
|
9808
|
-
async uploadEnv(devProjectId, file) {
|
|
9809
|
-
const formData = new FormData;
|
|
9810
|
-
formData.append("devProjectId", devProjectId);
|
|
9811
|
-
formData.append("file", file);
|
|
9812
|
-
const response = await this.api.post(`/uploadEnv/${devProjectId}`, formData);
|
|
9813
|
-
return response.success;
|
|
9814
|
-
}
|
|
9815
|
-
async downloadEnv(devProjectId) {
|
|
9816
|
-
const response = await this.api.get(`/downloadEnv/${devProjectId}`);
|
|
9817
|
-
return response.success;
|
|
9818
|
-
}
|
|
9819
|
-
async getRemoteAuthToken(remoteId) {
|
|
9820
|
-
if (this.#needRefreshToken())
|
|
9821
|
-
return await this.refreshAuthToken();
|
|
9822
|
-
else if (this.#accessToken)
|
|
9823
|
-
return this.#accessToken;
|
|
9824
|
-
const accessToken = await this.api.get(`/getRemoteAuthToken/${remoteId}`);
|
|
9825
|
-
this.#accessToken = {
|
|
9826
|
-
jwt: accessToken.jwt,
|
|
9827
|
-
refreshToken: accessToken.refreshToken,
|
|
9828
|
-
expiresAt: accessToken.expiresAt ? import_dayjs.default(accessToken.expiresAt) : null
|
|
9829
|
-
};
|
|
9830
|
-
return this.#accessToken;
|
|
9831
|
-
}
|
|
9832
|
-
async refreshAuthToken() {
|
|
9833
|
-
const response = await this.api.post(`/refreshRemoteAuthToken`, {
|
|
9834
|
-
refreshToken: this.#accessToken?.refreshToken
|
|
9835
|
-
});
|
|
9836
|
-
this.#accessToken = {
|
|
9837
|
-
jwt: response.jwt,
|
|
9838
|
-
refreshToken: response.refreshToken,
|
|
9839
|
-
expiresAt: response.expiresAt ? import_dayjs.default(response.expiresAt) : null
|
|
9840
|
-
};
|
|
9841
|
-
return this.#accessToken;
|
|
9842
|
-
}
|
|
9843
|
-
#needRefreshToken() {
|
|
9844
|
-
return !!this.#accessToken?.expiresAt?.isBefore(import_dayjs.default().add(1, "hour"));
|
|
9845
|
-
}
|
|
9846
|
-
}
|
|
9847
10052
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
|
|
9848
|
-
import { Logger as
|
|
10053
|
+
import { Logger as Logger11 } from "akanjs/common";
|
|
9849
10054
|
|
|
9850
10055
|
class IncrementalBuilder {
|
|
9851
|
-
#logger = new
|
|
10056
|
+
#logger = new Logger11("IncrementalBuilder");
|
|
9852
10057
|
#app;
|
|
9853
10058
|
#artifact;
|
|
9854
10059
|
#watch;
|