@backifydev/cli 0.3.1 → 0.3.3
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/README.md +6 -3
- package/dist/index.js +1010 -75
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1,35 +1,811 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/functions.ts
|
|
4
|
+
import { build } from "esbuild";
|
|
5
|
+
|
|
6
|
+
// ../../node_modules/fflate/esm/index.mjs
|
|
7
|
+
import { createRequire } from "module";
|
|
8
|
+
var require2 = createRequire("/");
|
|
9
|
+
var _a;
|
|
10
|
+
var Worker;
|
|
11
|
+
var isMarkedAsUntransferable;
|
|
12
|
+
try {
|
|
13
|
+
_a = require2("worker_threads"), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable;
|
|
14
|
+
} catch (e) {
|
|
15
|
+
}
|
|
16
|
+
var u8 = Uint8Array;
|
|
17
|
+
var u16 = Uint16Array;
|
|
18
|
+
var i32 = Int32Array;
|
|
19
|
+
var fleb = new u8([
|
|
20
|
+
0,
|
|
21
|
+
0,
|
|
22
|
+
0,
|
|
23
|
+
0,
|
|
24
|
+
0,
|
|
25
|
+
0,
|
|
26
|
+
0,
|
|
27
|
+
0,
|
|
28
|
+
1,
|
|
29
|
+
1,
|
|
30
|
+
1,
|
|
31
|
+
1,
|
|
32
|
+
2,
|
|
33
|
+
2,
|
|
34
|
+
2,
|
|
35
|
+
2,
|
|
36
|
+
3,
|
|
37
|
+
3,
|
|
38
|
+
3,
|
|
39
|
+
3,
|
|
40
|
+
4,
|
|
41
|
+
4,
|
|
42
|
+
4,
|
|
43
|
+
4,
|
|
44
|
+
5,
|
|
45
|
+
5,
|
|
46
|
+
5,
|
|
47
|
+
5,
|
|
48
|
+
0,
|
|
49
|
+
/* unused */
|
|
50
|
+
0,
|
|
51
|
+
0,
|
|
52
|
+
/* impossible */
|
|
53
|
+
0
|
|
54
|
+
]);
|
|
55
|
+
var fdeb = new u8([
|
|
56
|
+
0,
|
|
57
|
+
0,
|
|
58
|
+
0,
|
|
59
|
+
0,
|
|
60
|
+
1,
|
|
61
|
+
1,
|
|
62
|
+
2,
|
|
63
|
+
2,
|
|
64
|
+
3,
|
|
65
|
+
3,
|
|
66
|
+
4,
|
|
67
|
+
4,
|
|
68
|
+
5,
|
|
69
|
+
5,
|
|
70
|
+
6,
|
|
71
|
+
6,
|
|
72
|
+
7,
|
|
73
|
+
7,
|
|
74
|
+
8,
|
|
75
|
+
8,
|
|
76
|
+
9,
|
|
77
|
+
9,
|
|
78
|
+
10,
|
|
79
|
+
10,
|
|
80
|
+
11,
|
|
81
|
+
11,
|
|
82
|
+
12,
|
|
83
|
+
12,
|
|
84
|
+
13,
|
|
85
|
+
13,
|
|
86
|
+
/* unused */
|
|
87
|
+
0,
|
|
88
|
+
0
|
|
89
|
+
]);
|
|
90
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
91
|
+
var freb = function(eb, start) {
|
|
92
|
+
var b = new u16(31);
|
|
93
|
+
for (var i = 0; i < 31; ++i) {
|
|
94
|
+
b[i] = start += 1 << eb[i - 1];
|
|
95
|
+
}
|
|
96
|
+
var r = new i32(b[30]);
|
|
97
|
+
for (var i = 1; i < 30; ++i) {
|
|
98
|
+
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
99
|
+
r[j] = j - b[i] << 5 | i;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { b, r };
|
|
103
|
+
};
|
|
104
|
+
var _a = freb(fleb, 2);
|
|
105
|
+
var fl = _a.b;
|
|
106
|
+
var revfl = _a.r;
|
|
107
|
+
fl[28] = 258, revfl[258] = 28;
|
|
108
|
+
var _b = freb(fdeb, 0);
|
|
109
|
+
var fd = _b.b;
|
|
110
|
+
var revfd = _b.r;
|
|
111
|
+
var rev = new u16(32768);
|
|
112
|
+
for (i = 0; i < 32768; ++i) {
|
|
113
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
114
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
115
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
116
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
117
|
+
}
|
|
118
|
+
var x;
|
|
119
|
+
var i;
|
|
120
|
+
var hMap = (function(cd, mb, r) {
|
|
121
|
+
var s = cd.length;
|
|
122
|
+
var i = 0;
|
|
123
|
+
var l = new u16(mb);
|
|
124
|
+
for (; i < s; ++i) {
|
|
125
|
+
if (cd[i])
|
|
126
|
+
++l[cd[i] - 1];
|
|
127
|
+
}
|
|
128
|
+
var le = new u16(mb);
|
|
129
|
+
for (i = 1; i < mb; ++i) {
|
|
130
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
131
|
+
}
|
|
132
|
+
var co;
|
|
133
|
+
if (r) {
|
|
134
|
+
co = new u16(1 << mb);
|
|
135
|
+
var rvb = 15 - mb;
|
|
136
|
+
for (i = 0; i < s; ++i) {
|
|
137
|
+
if (cd[i]) {
|
|
138
|
+
var sv = i << 4 | cd[i];
|
|
139
|
+
var r_1 = mb - cd[i];
|
|
140
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
141
|
+
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
|
|
142
|
+
co[rev[v] >> rvb] = sv;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
co = new u16(s);
|
|
148
|
+
for (i = 0; i < s; ++i) {
|
|
149
|
+
if (cd[i]) {
|
|
150
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return co;
|
|
155
|
+
});
|
|
156
|
+
var flt = new u8(288);
|
|
157
|
+
for (i = 0; i < 144; ++i)
|
|
158
|
+
flt[i] = 8;
|
|
159
|
+
var i;
|
|
160
|
+
for (i = 144; i < 256; ++i)
|
|
161
|
+
flt[i] = 9;
|
|
162
|
+
var i;
|
|
163
|
+
for (i = 256; i < 280; ++i)
|
|
164
|
+
flt[i] = 7;
|
|
165
|
+
var i;
|
|
166
|
+
for (i = 280; i < 288; ++i)
|
|
167
|
+
flt[i] = 8;
|
|
168
|
+
var i;
|
|
169
|
+
var fdt = new u8(32);
|
|
170
|
+
for (i = 0; i < 32; ++i)
|
|
171
|
+
fdt[i] = 5;
|
|
172
|
+
var i;
|
|
173
|
+
var flm = /* @__PURE__ */ hMap(flt, 9, 0);
|
|
174
|
+
var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
|
|
175
|
+
var shft = function(p) {
|
|
176
|
+
return (p + 7) / 8 | 0;
|
|
177
|
+
};
|
|
178
|
+
var slc = function(v, s, e) {
|
|
179
|
+
if (s == null || s < 0)
|
|
180
|
+
s = 0;
|
|
181
|
+
if (e == null || e > v.length)
|
|
182
|
+
e = v.length;
|
|
183
|
+
return new u8(v.subarray(s, e));
|
|
184
|
+
};
|
|
185
|
+
var ec = [
|
|
186
|
+
"unexpected EOF",
|
|
187
|
+
"invalid block type",
|
|
188
|
+
"invalid length/literal",
|
|
189
|
+
"invalid distance",
|
|
190
|
+
"stream finished",
|
|
191
|
+
"no stream handler",
|
|
192
|
+
,
|
|
193
|
+
// determined by compression function
|
|
194
|
+
"no callback",
|
|
195
|
+
"invalid UTF-8 data",
|
|
196
|
+
"extra field too long",
|
|
197
|
+
"date not in range 1980-2099",
|
|
198
|
+
"filename too long",
|
|
199
|
+
"stream finishing",
|
|
200
|
+
"invalid zip data"
|
|
201
|
+
// determined by unknown compression method
|
|
202
|
+
];
|
|
203
|
+
var err = function(ind, msg, nt) {
|
|
204
|
+
var e = new Error(msg || ec[ind]);
|
|
205
|
+
e.code = ind;
|
|
206
|
+
if (Error.captureStackTrace)
|
|
207
|
+
Error.captureStackTrace(e, err);
|
|
208
|
+
if (!nt)
|
|
209
|
+
throw e;
|
|
210
|
+
return e;
|
|
211
|
+
};
|
|
212
|
+
var wbits = function(d, p, v) {
|
|
213
|
+
v <<= p & 7;
|
|
214
|
+
var o = p / 8 | 0;
|
|
215
|
+
d[o] |= v;
|
|
216
|
+
d[o + 1] |= v >> 8;
|
|
217
|
+
};
|
|
218
|
+
var wbits16 = function(d, p, v) {
|
|
219
|
+
v <<= p & 7;
|
|
220
|
+
var o = p / 8 | 0;
|
|
221
|
+
d[o] |= v;
|
|
222
|
+
d[o + 1] |= v >> 8;
|
|
223
|
+
d[o + 2] |= v >> 16;
|
|
224
|
+
};
|
|
225
|
+
var hTree = function(d, mb) {
|
|
226
|
+
var t = [];
|
|
227
|
+
for (var i = 0; i < d.length; ++i) {
|
|
228
|
+
if (d[i])
|
|
229
|
+
t.push({ s: i, f: d[i] });
|
|
230
|
+
}
|
|
231
|
+
var s = t.length;
|
|
232
|
+
var t2 = t.slice();
|
|
233
|
+
if (!s)
|
|
234
|
+
return { t: et, l: 0 };
|
|
235
|
+
if (s == 1) {
|
|
236
|
+
var v = new u8(t[0].s + 1);
|
|
237
|
+
v[t[0].s] = 1;
|
|
238
|
+
return { t: v, l: 1 };
|
|
239
|
+
}
|
|
240
|
+
t.sort(function(a, b) {
|
|
241
|
+
return a.f - b.f;
|
|
242
|
+
});
|
|
243
|
+
t.push({ s: -1, f: 25001 });
|
|
244
|
+
var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;
|
|
245
|
+
t[0] = { s: -1, f: l.f + r.f, l, r };
|
|
246
|
+
while (i1 != s - 1) {
|
|
247
|
+
l = t[t[i0].f < t[i2].f ? i0++ : i2++];
|
|
248
|
+
r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];
|
|
249
|
+
t[i1++] = { s: -1, f: l.f + r.f, l, r };
|
|
250
|
+
}
|
|
251
|
+
var maxSym = t2[0].s;
|
|
252
|
+
for (var i = 1; i < s; ++i) {
|
|
253
|
+
if (t2[i].s > maxSym)
|
|
254
|
+
maxSym = t2[i].s;
|
|
255
|
+
}
|
|
256
|
+
var tr = new u16(maxSym + 1);
|
|
257
|
+
var mbt = ln(t[i1 - 1], tr, 0);
|
|
258
|
+
if (mbt > mb) {
|
|
259
|
+
var i = 0, dt = 0;
|
|
260
|
+
var lft = mbt - mb, cst = 1 << lft;
|
|
261
|
+
t2.sort(function(a, b) {
|
|
262
|
+
return tr[b.s] - tr[a.s] || a.f - b.f;
|
|
263
|
+
});
|
|
264
|
+
for (; i < s; ++i) {
|
|
265
|
+
var i2_1 = t2[i].s;
|
|
266
|
+
if (tr[i2_1] > mb) {
|
|
267
|
+
dt += cst - (1 << mbt - tr[i2_1]);
|
|
268
|
+
tr[i2_1] = mb;
|
|
269
|
+
} else
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
dt >>= lft;
|
|
273
|
+
while (dt > 0) {
|
|
274
|
+
var i2_2 = t2[i].s;
|
|
275
|
+
if (tr[i2_2] < mb)
|
|
276
|
+
dt -= 1 << mb - tr[i2_2]++ - 1;
|
|
277
|
+
else
|
|
278
|
+
++i;
|
|
279
|
+
}
|
|
280
|
+
for (; i >= 0 && dt; --i) {
|
|
281
|
+
var i2_3 = t2[i].s;
|
|
282
|
+
if (tr[i2_3] == mb) {
|
|
283
|
+
--tr[i2_3];
|
|
284
|
+
++dt;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
mbt = mb;
|
|
288
|
+
}
|
|
289
|
+
return { t: new u8(tr), l: mbt };
|
|
290
|
+
};
|
|
291
|
+
var ln = function(n, l, d) {
|
|
292
|
+
return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
|
|
293
|
+
};
|
|
294
|
+
var lc = function(c) {
|
|
295
|
+
var s = c.length;
|
|
296
|
+
while (s && !c[--s])
|
|
297
|
+
;
|
|
298
|
+
var cl = new u16(++s);
|
|
299
|
+
var cli = 0, cln = c[0], cls = 1;
|
|
300
|
+
var w = function(v) {
|
|
301
|
+
cl[cli++] = v;
|
|
302
|
+
};
|
|
303
|
+
for (var i = 1; i <= s; ++i) {
|
|
304
|
+
if (c[i] == cln && i != s)
|
|
305
|
+
++cls;
|
|
306
|
+
else {
|
|
307
|
+
if (!cln && cls > 2) {
|
|
308
|
+
for (; cls > 138; cls -= 138)
|
|
309
|
+
w(32754);
|
|
310
|
+
if (cls > 2) {
|
|
311
|
+
w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
|
|
312
|
+
cls = 0;
|
|
313
|
+
}
|
|
314
|
+
} else if (cls > 3) {
|
|
315
|
+
w(cln), --cls;
|
|
316
|
+
for (; cls > 6; cls -= 6)
|
|
317
|
+
w(8304);
|
|
318
|
+
if (cls > 2)
|
|
319
|
+
w(cls - 3 << 5 | 8208), cls = 0;
|
|
320
|
+
}
|
|
321
|
+
while (cls--)
|
|
322
|
+
w(cln);
|
|
323
|
+
cls = 1;
|
|
324
|
+
cln = c[i];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return { c: cl.subarray(0, cli), n: s };
|
|
328
|
+
};
|
|
329
|
+
var clen = function(cf, cl) {
|
|
330
|
+
var l = 0;
|
|
331
|
+
for (var i = 0; i < cl.length; ++i)
|
|
332
|
+
l += cf[i] * cl[i];
|
|
333
|
+
return l;
|
|
334
|
+
};
|
|
335
|
+
var wfblk = function(out, pos, dat) {
|
|
336
|
+
var s = dat.length;
|
|
337
|
+
var o = shft(pos + 2);
|
|
338
|
+
out[o] = s & 255;
|
|
339
|
+
out[o + 1] = s >> 8;
|
|
340
|
+
out[o + 2] = out[o] ^ 255;
|
|
341
|
+
out[o + 3] = out[o + 1] ^ 255;
|
|
342
|
+
for (var i = 0; i < s; ++i)
|
|
343
|
+
out[o + i + 4] = dat[i];
|
|
344
|
+
return (o + 4 + s) * 8;
|
|
345
|
+
};
|
|
346
|
+
var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
|
|
347
|
+
wbits(out, p++, final);
|
|
348
|
+
++lf[256];
|
|
349
|
+
var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
|
|
350
|
+
var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
|
|
351
|
+
var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
|
|
352
|
+
var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
|
|
353
|
+
var lcfreq = new u16(19);
|
|
354
|
+
for (var i = 0; i < lclt.length; ++i)
|
|
355
|
+
++lcfreq[lclt[i] & 31];
|
|
356
|
+
for (var i = 0; i < lcdt.length; ++i)
|
|
357
|
+
++lcfreq[lcdt[i] & 31];
|
|
358
|
+
var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
|
|
359
|
+
var nlcc = 19;
|
|
360
|
+
for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
|
|
361
|
+
;
|
|
362
|
+
var flen = bl + 5 << 3;
|
|
363
|
+
var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
|
|
364
|
+
var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
|
|
365
|
+
if (bs >= 0 && flen <= ftlen && flen <= dtlen)
|
|
366
|
+
return wfblk(out, p, dat.subarray(bs, bs + bl));
|
|
367
|
+
var lm, ll, dm, dl;
|
|
368
|
+
wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
|
|
369
|
+
if (dtlen < ftlen) {
|
|
370
|
+
lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
|
|
371
|
+
var llm = hMap(lct, mlcb, 0);
|
|
372
|
+
wbits(out, p, nlc - 257);
|
|
373
|
+
wbits(out, p + 5, ndc - 1);
|
|
374
|
+
wbits(out, p + 10, nlcc - 4);
|
|
375
|
+
p += 14;
|
|
376
|
+
for (var i = 0; i < nlcc; ++i)
|
|
377
|
+
wbits(out, p + 3 * i, lct[clim[i]]);
|
|
378
|
+
p += 3 * nlcc;
|
|
379
|
+
var lcts = [lclt, lcdt];
|
|
380
|
+
for (var it = 0; it < 2; ++it) {
|
|
381
|
+
var clct = lcts[it];
|
|
382
|
+
for (var i = 0; i < clct.length; ++i) {
|
|
383
|
+
var len = clct[i] & 31;
|
|
384
|
+
wbits(out, p, llm[len]), p += lct[len];
|
|
385
|
+
if (len > 15)
|
|
386
|
+
wbits(out, p, clct[i] >> 5 & 127), p += clct[i] >> 12;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
lm = flm, ll = flt, dm = fdm, dl = fdt;
|
|
391
|
+
}
|
|
392
|
+
for (var i = 0; i < li; ++i) {
|
|
393
|
+
var sym = syms[i];
|
|
394
|
+
if (sym > 255) {
|
|
395
|
+
var len = sym >> 18 & 31;
|
|
396
|
+
wbits16(out, p, lm[len + 257]), p += ll[len + 257];
|
|
397
|
+
if (len > 7)
|
|
398
|
+
wbits(out, p, sym >> 23 & 31), p += fleb[len];
|
|
399
|
+
var dst = sym & 31;
|
|
400
|
+
wbits16(out, p, dm[dst]), p += dl[dst];
|
|
401
|
+
if (dst > 3)
|
|
402
|
+
wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
|
|
403
|
+
} else {
|
|
404
|
+
wbits16(out, p, lm[sym]), p += ll[sym];
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
wbits16(out, p, lm[256]);
|
|
408
|
+
return p + ll[256];
|
|
409
|
+
};
|
|
410
|
+
var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
|
|
411
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
412
|
+
var dflt = function(dat, lvl, plvl, pre, post, st) {
|
|
413
|
+
var s = st.z || dat.length;
|
|
414
|
+
var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
|
|
415
|
+
var w = o.subarray(pre, o.length - post);
|
|
416
|
+
var lst = st.l;
|
|
417
|
+
var pos = (st.r || 0) & 7;
|
|
418
|
+
if (lvl) {
|
|
419
|
+
if (pos)
|
|
420
|
+
w[0] = st.r >> 3;
|
|
421
|
+
var opt = deo[lvl - 1];
|
|
422
|
+
var n = opt >> 13, c = opt & 8191;
|
|
423
|
+
var msk_1 = (1 << plvl) - 1;
|
|
424
|
+
var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
|
|
425
|
+
var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
|
|
426
|
+
var hsh = function(i2) {
|
|
427
|
+
return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1;
|
|
428
|
+
};
|
|
429
|
+
var syms = new i32(25e3);
|
|
430
|
+
var lf = new u16(288), df = new u16(32);
|
|
431
|
+
var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
|
|
432
|
+
for (; i + 2 < s; ++i) {
|
|
433
|
+
var hv = hsh(i);
|
|
434
|
+
var imod = i & 32767, pimod = head[hv];
|
|
435
|
+
prev[imod] = pimod;
|
|
436
|
+
head[hv] = imod;
|
|
437
|
+
if (wi <= i) {
|
|
438
|
+
var rem = s - i;
|
|
439
|
+
if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
|
|
440
|
+
pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
441
|
+
li = lc_1 = eb = 0, bs = i;
|
|
442
|
+
for (var j = 0; j < 286; ++j)
|
|
443
|
+
lf[j] = 0;
|
|
444
|
+
for (var j = 0; j < 30; ++j)
|
|
445
|
+
df[j] = 0;
|
|
446
|
+
}
|
|
447
|
+
var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
|
|
448
|
+
if (rem > 2 && hv == hsh(i - dif)) {
|
|
449
|
+
var maxn = Math.min(n, rem) - 1;
|
|
450
|
+
var maxd = Math.min(32767, i);
|
|
451
|
+
var ml = Math.min(258, rem);
|
|
452
|
+
while (dif <= maxd && --ch_1 && imod != pimod) {
|
|
453
|
+
if (dat[i + l] == dat[i + l - dif]) {
|
|
454
|
+
var nl = 0;
|
|
455
|
+
for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)
|
|
456
|
+
;
|
|
457
|
+
if (nl > l) {
|
|
458
|
+
l = nl, d = dif;
|
|
459
|
+
if (nl > maxn)
|
|
460
|
+
break;
|
|
461
|
+
var mmd = Math.min(dif, nl - 2);
|
|
462
|
+
var md = 0;
|
|
463
|
+
for (var j = 0; j < mmd; ++j) {
|
|
464
|
+
var ti = i - dif + j & 32767;
|
|
465
|
+
var pti = prev[ti];
|
|
466
|
+
var cd = ti - pti & 32767;
|
|
467
|
+
if (cd > md)
|
|
468
|
+
md = cd, pimod = ti;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
imod = pimod, pimod = prev[imod];
|
|
473
|
+
dif += imod - pimod & 32767;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (d) {
|
|
477
|
+
syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
|
|
478
|
+
var lin = revfl[l] & 31, din = revfd[d] & 31;
|
|
479
|
+
eb += fleb[lin] + fdeb[din];
|
|
480
|
+
++lf[257 + lin];
|
|
481
|
+
++df[din];
|
|
482
|
+
wi = i + l;
|
|
483
|
+
++lc_1;
|
|
484
|
+
} else {
|
|
485
|
+
syms[li++] = dat[i];
|
|
486
|
+
++lf[dat[i]];
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
for (i = Math.max(i, wi); i < s; ++i) {
|
|
491
|
+
syms[li++] = dat[i];
|
|
492
|
+
++lf[dat[i]];
|
|
493
|
+
}
|
|
494
|
+
pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
495
|
+
if (!lst) {
|
|
496
|
+
st.r = pos & 7 | w[pos / 8 | 0] << 3;
|
|
497
|
+
pos -= 7;
|
|
498
|
+
st.h = head, st.p = prev, st.i = i, st.w = wi;
|
|
499
|
+
}
|
|
500
|
+
} else {
|
|
501
|
+
for (var i = st.w || 0; i < s + lst; i += 65535) {
|
|
502
|
+
var e = i + 65535;
|
|
503
|
+
if (e >= s) {
|
|
504
|
+
w[pos / 8 | 0] = lst;
|
|
505
|
+
e = s;
|
|
506
|
+
}
|
|
507
|
+
pos = wfblk(w, pos + 1, dat.subarray(i, e));
|
|
508
|
+
}
|
|
509
|
+
st.i = s;
|
|
510
|
+
}
|
|
511
|
+
return slc(o, 0, pre + shft(pos) + post);
|
|
512
|
+
};
|
|
513
|
+
var crct = /* @__PURE__ */ (function() {
|
|
514
|
+
var t = new Int32Array(256);
|
|
515
|
+
for (var i = 0; i < 256; ++i) {
|
|
516
|
+
var c = i, k = 9;
|
|
517
|
+
while (--k)
|
|
518
|
+
c = (c & 1 && -306674912) ^ c >>> 1;
|
|
519
|
+
t[i] = c;
|
|
520
|
+
}
|
|
521
|
+
return t;
|
|
522
|
+
})();
|
|
523
|
+
var crc = function() {
|
|
524
|
+
var c = -1;
|
|
525
|
+
return {
|
|
526
|
+
p: function(d) {
|
|
527
|
+
var cr = c;
|
|
528
|
+
for (var i = 0; i < d.length; ++i)
|
|
529
|
+
cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8;
|
|
530
|
+
c = cr;
|
|
531
|
+
},
|
|
532
|
+
d: function() {
|
|
533
|
+
return ~c;
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
var dopt = function(dat, opt, pre, post, st) {
|
|
538
|
+
if (!st) {
|
|
539
|
+
st = { l: 1 };
|
|
540
|
+
if (opt.dictionary) {
|
|
541
|
+
var dict = opt.dictionary.subarray(-32768);
|
|
542
|
+
var newDat = new u8(dict.length + dat.length);
|
|
543
|
+
newDat.set(dict);
|
|
544
|
+
newDat.set(dat, dict.length);
|
|
545
|
+
dat = newDat;
|
|
546
|
+
st.w = dict.length;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
|
|
550
|
+
};
|
|
551
|
+
var mrg = function(a, b) {
|
|
552
|
+
var o = {};
|
|
553
|
+
for (var k in a)
|
|
554
|
+
o[k] = a[k];
|
|
555
|
+
for (var k in b)
|
|
556
|
+
o[k] = b[k];
|
|
557
|
+
return o;
|
|
558
|
+
};
|
|
559
|
+
var wbytes = function(d, b, v) {
|
|
560
|
+
for (; v; ++b)
|
|
561
|
+
d[b] = v, v >>>= 8;
|
|
562
|
+
};
|
|
563
|
+
function deflateSync(data, opts) {
|
|
564
|
+
return dopt(data, opts || {}, 0, 0);
|
|
565
|
+
}
|
|
566
|
+
var fltn = function(d, p, t, o) {
|
|
567
|
+
for (var k in d) {
|
|
568
|
+
var val = d[k], n = p + k, op = o;
|
|
569
|
+
if (Array.isArray(val))
|
|
570
|
+
op = mrg(o, val[1]), val = val[0];
|
|
571
|
+
if (ArrayBuffer.isView(val))
|
|
572
|
+
t[n] = [val, op];
|
|
573
|
+
else {
|
|
574
|
+
t[n += "/"] = [new u8(0), op];
|
|
575
|
+
fltn(val, n, t, o);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
|
|
580
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
581
|
+
var tds = 0;
|
|
582
|
+
try {
|
|
583
|
+
td.decode(et, { stream: true });
|
|
584
|
+
tds = 1;
|
|
585
|
+
} catch (e) {
|
|
586
|
+
}
|
|
587
|
+
function strToU8(str, latin1) {
|
|
588
|
+
if (latin1) {
|
|
589
|
+
var ar_1 = new u8(str.length);
|
|
590
|
+
for (var i = 0; i < str.length; ++i)
|
|
591
|
+
ar_1[i] = str.charCodeAt(i);
|
|
592
|
+
return ar_1;
|
|
593
|
+
}
|
|
594
|
+
if (te)
|
|
595
|
+
return te.encode(str);
|
|
596
|
+
var l = str.length;
|
|
597
|
+
var ar = new u8(str.length + (str.length >> 1));
|
|
598
|
+
var ai = 0;
|
|
599
|
+
var w = function(v) {
|
|
600
|
+
ar[ai++] = v;
|
|
601
|
+
};
|
|
602
|
+
for (var i = 0; i < l; ++i) {
|
|
603
|
+
if (ai + 5 > ar.length) {
|
|
604
|
+
var n = new u8(ai + 8 + (l - i << 1));
|
|
605
|
+
n.set(ar);
|
|
606
|
+
ar = n;
|
|
607
|
+
}
|
|
608
|
+
var c = str.charCodeAt(i);
|
|
609
|
+
if (c < 128 || latin1)
|
|
610
|
+
w(c);
|
|
611
|
+
else if (c < 2048)
|
|
612
|
+
w(192 | c >> 6), w(128 | c & 63);
|
|
613
|
+
else if (c > 55295 && c < 57344)
|
|
614
|
+
c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
615
|
+
else
|
|
616
|
+
w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
617
|
+
}
|
|
618
|
+
return slc(ar, 0, ai);
|
|
619
|
+
}
|
|
620
|
+
var exfl = function(ex) {
|
|
621
|
+
var le = 0;
|
|
622
|
+
if (ex) {
|
|
623
|
+
for (var k in ex) {
|
|
624
|
+
var l = ex[k].length;
|
|
625
|
+
if (l > 65535)
|
|
626
|
+
err(9);
|
|
627
|
+
le += l + 4;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return le;
|
|
631
|
+
};
|
|
632
|
+
var wzh = function(d, b, f, fn, u, c, ce, co) {
|
|
633
|
+
var fl2 = fn.length, ex = f.extra, col = co && co.length;
|
|
634
|
+
var exl = exfl(ex);
|
|
635
|
+
wbytes(d, b, ce != null ? 33639248 : 67324752), b += 4;
|
|
636
|
+
if (ce != null)
|
|
637
|
+
d[b++] = 20, d[b++] = f.os;
|
|
638
|
+
d[b] = 20, b += 2;
|
|
639
|
+
d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8;
|
|
640
|
+
d[b++] = f.compression & 255, d[b++] = f.compression >> 8;
|
|
641
|
+
var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;
|
|
642
|
+
if (y < 0 || y > 119)
|
|
643
|
+
err(10);
|
|
644
|
+
wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >> 1), b += 4;
|
|
645
|
+
if (c != -1) {
|
|
646
|
+
wbytes(d, b, f.crc);
|
|
647
|
+
wbytes(d, b + 4, c < 0 ? -c - 2 : c);
|
|
648
|
+
wbytes(d, b + 8, f.size);
|
|
649
|
+
}
|
|
650
|
+
wbytes(d, b + 12, fl2);
|
|
651
|
+
wbytes(d, b + 14, exl), b += 16;
|
|
652
|
+
if (ce != null) {
|
|
653
|
+
wbytes(d, b, col);
|
|
654
|
+
wbytes(d, b + 6, f.attrs);
|
|
655
|
+
wbytes(d, b + 10, ce), b += 14;
|
|
656
|
+
}
|
|
657
|
+
d.set(fn, b);
|
|
658
|
+
b += fl2;
|
|
659
|
+
if (exl) {
|
|
660
|
+
for (var k in ex) {
|
|
661
|
+
var exf = ex[k], l = exf.length;
|
|
662
|
+
wbytes(d, b, +k);
|
|
663
|
+
wbytes(d, b + 2, l);
|
|
664
|
+
d.set(exf, b + 4), b += 4 + l;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (col)
|
|
668
|
+
d.set(co, b), b += col;
|
|
669
|
+
return b;
|
|
670
|
+
};
|
|
671
|
+
var wzf = function(o, b, c, d, e) {
|
|
672
|
+
wbytes(o, b, 101010256);
|
|
673
|
+
wbytes(o, b + 8, c);
|
|
674
|
+
wbytes(o, b + 10, c);
|
|
675
|
+
wbytes(o, b + 12, d);
|
|
676
|
+
wbytes(o, b + 16, e);
|
|
677
|
+
};
|
|
678
|
+
function zipSync(data, opts) {
|
|
679
|
+
if (!opts)
|
|
680
|
+
opts = {};
|
|
681
|
+
var r = {};
|
|
682
|
+
var files = [];
|
|
683
|
+
fltn(data, "", r, opts);
|
|
684
|
+
var o = 0;
|
|
685
|
+
var tot = 0;
|
|
686
|
+
for (var fn in r) {
|
|
687
|
+
var _a2 = r[fn], file = _a2[0], p = _a2[1];
|
|
688
|
+
var compression = p.level == 0 ? 0 : 8;
|
|
689
|
+
var f = strToU8(fn), s = f.length;
|
|
690
|
+
var com = p.comment, m = com && strToU8(com), ms = m && m.length;
|
|
691
|
+
var exl = exfl(p.extra);
|
|
692
|
+
if (s > 65535)
|
|
693
|
+
err(11);
|
|
694
|
+
var d = compression ? deflateSync(file, p) : file, l = d.length;
|
|
695
|
+
var c = crc();
|
|
696
|
+
c.p(file);
|
|
697
|
+
files.push(mrg(p, {
|
|
698
|
+
size: file.length,
|
|
699
|
+
crc: c.d(),
|
|
700
|
+
c: d,
|
|
701
|
+
f,
|
|
702
|
+
m,
|
|
703
|
+
u: s != fn.length || m && com.length != ms,
|
|
704
|
+
o,
|
|
705
|
+
compression
|
|
706
|
+
}));
|
|
707
|
+
o += 30 + s + exl + l;
|
|
708
|
+
tot += 76 + 2 * (s + exl) + (ms || 0) + l;
|
|
709
|
+
}
|
|
710
|
+
var out = new u8(tot + 22), oe = o, cdl = tot - o;
|
|
711
|
+
for (var i = 0; i < files.length; ++i) {
|
|
712
|
+
var f = files[i];
|
|
713
|
+
wzh(out, f.o, f, f.f, f.u, f.c.length);
|
|
714
|
+
var badd = 30 + f.f.length + exfl(f.extra);
|
|
715
|
+
out.set(f.c, f.o + badd);
|
|
716
|
+
wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);
|
|
717
|
+
}
|
|
718
|
+
wzf(out, o, files.length, cdl, oe);
|
|
719
|
+
return out;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// src/functions.ts
|
|
723
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
724
|
+
import { dirname, resolve } from "node:path";
|
|
725
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
726
|
+
async function packageFunctions(entry, output) {
|
|
727
|
+
const entryPath = resolve(entry);
|
|
728
|
+
if (!existsSync(entryPath)) throw new Error("Function entrypoint does not exist: " + entryPath);
|
|
729
|
+
const require3 = createRequire2(import.meta.url);
|
|
730
|
+
const azureFunctions = require3.resolve("@azure/functions");
|
|
731
|
+
const result = await build({
|
|
732
|
+
stdin: {
|
|
733
|
+
contents: [
|
|
734
|
+
"import { app } from " + JSON.stringify(azureFunctions) + ";",
|
|
735
|
+
'import { createAzureFunctionHandler } from "@backifydev/sdk";',
|
|
736
|
+
"import * as declarations from " + JSON.stringify(entryPath) + ";",
|
|
737
|
+
"const registered = new Set();",
|
|
738
|
+
"for (const [exportName, definition] of Object.entries(declarations)) {",
|
|
739
|
+
" if (!definition || definition.__backify?.capability !== 'functions') continue;",
|
|
740
|
+
" const name = definition.name ?? exportName;",
|
|
741
|
+
" if (!/^[A-Za-z][A-Za-z0-9_-]{0,99}$/.test(name) || registered.has(name)) throw new Error('Invalid or duplicate function name: ' + name);",
|
|
742
|
+
" registered.add(name);",
|
|
743
|
+
" app.http(name, { methods: ['POST'], authLevel: 'function', handler: createAzureFunctionHandler(definition) });",
|
|
744
|
+
"}",
|
|
745
|
+
"if (!registered.size) throw new Error('Export at least one Backify function declaration');"
|
|
746
|
+
].join("\n"),
|
|
747
|
+
resolveDir: dirname(entryPath),
|
|
748
|
+
sourcefile: "backify-functions-host.ts",
|
|
749
|
+
loader: "ts"
|
|
750
|
+
},
|
|
751
|
+
bundle: true,
|
|
752
|
+
platform: "node",
|
|
753
|
+
target: "node22",
|
|
754
|
+
format: "cjs",
|
|
755
|
+
write: false,
|
|
756
|
+
external: ["@azure/functions-core"],
|
|
757
|
+
outfile: "index.cjs",
|
|
758
|
+
sourcemap: false
|
|
759
|
+
});
|
|
760
|
+
const archive = zipSync({
|
|
761
|
+
"index.cjs": result.outputFiles[0].contents,
|
|
762
|
+
"host.json": strToU8(JSON.stringify({ version: "2.0" })),
|
|
763
|
+
"package.json": strToU8(JSON.stringify({ name: "backify-functions", version: "1.0.0", main: "index.cjs", private: true }))
|
|
764
|
+
});
|
|
765
|
+
const outputPath = resolve(output);
|
|
766
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
767
|
+
writeFileSync(outputPath, archive);
|
|
768
|
+
return outputPath;
|
|
769
|
+
}
|
|
770
|
+
|
|
3
771
|
// src/development.ts
|
|
4
|
-
import { existsSync as
|
|
5
|
-
import { join as join3, resolve as
|
|
772
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as writeFileSync4, renameSync, rmSync, mkdtempSync, lstatSync as lstatSync2, cpSync } from "node:fs";
|
|
773
|
+
import { dirname as dirname4, join as join3, resolve as resolve3 } from "node:path";
|
|
6
774
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7
775
|
import { randomUUID } from "node:crypto";
|
|
8
776
|
|
|
9
777
|
// src/setup.ts
|
|
10
|
-
import { existsSync as
|
|
11
|
-
import { basename, dirname, join as join2, resolve } from "node:path";
|
|
778
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, readdirSync, lstatSync } from "node:fs";
|
|
779
|
+
import { basename, dirname as dirname3, join as join2, resolve as resolve2, isAbsolute } from "node:path";
|
|
12
780
|
import { spawnSync } from "node:child_process";
|
|
13
781
|
|
|
14
782
|
// ../platform/dist/delivery.js
|
|
15
783
|
var deliveryInstructions = `# Backify application delivery and prompt history
|
|
16
784
|
|
|
17
|
-
Instruction version:
|
|
18
|
-
Versioned guide: https://agent.backify.dev/
|
|
785
|
+
Instruction version: 4
|
|
786
|
+
Versioned guide: https://agent.backify.dev/v4/delivery.md
|
|
19
787
|
|
|
20
788
|
These instructions are for AI coding tools building applications on Backify, not the Backify platform implementation. Complete the application and deliver a verified deployment, not just SDK setup. Respect the coding tool's own permissions and confirmation settings; preserve unrelated work and applicable repository instructions.
|
|
21
789
|
|
|
22
790
|
## Connect and initialize
|
|
23
791
|
|
|
24
|
-
|
|
792
|
+
The copied Backify prompt supplies App Id, Organization, and, when available, Pair, plus this guide reference and a privacy warning. Substitute those values for <app-id>, <organization-id>, and <pairing-code> below; never invent them. Use npx @backifydev/cli@latest so tool-specific setup and metadata-preserving cloning are available. The public API URL is https://api.backify.dev/api. For a nonproduction environment, replace the --api value with an explicitly trusted endpoint, or omit --api when using a trusted BACKIFY_API_URL override; never send a pairing code to an unverified endpoint.
|
|
793
|
+
|
|
794
|
+
npx @backifydev/cli@latest connect --app <app-id> --organization <organization-id> --api https://api.backify.dev/api --pair <pairing-code>
|
|
795
|
+
|
|
796
|
+
If Pair is absent, omit --pair and use CLI browser login. Pairing expires after 15 minutes. Never record the code or setup prompt in project files, Git, prompt history, or logs. The CLI stores an application-scoped session outside the repository. If access expires, obtain a new setup prompt or use CLI browser login.
|
|
25
797
|
|
|
26
|
-
|
|
798
|
+
Before connecting, inspect the current folder. If it is not a Git repository, is missing its .git directory or file, or has no Git remote, add --clone to the connect command. Default AI coding-tool directories and instruction files do not make a workspace an existing application. Run connect --clone in the current folder even when tool scaffolding exists, including configuration, rules, agents, skills, commands, prompts, and work/output directories. This is tool-independent: preserve the current tool's metadata and instructions regardless of its name; never delete or overwrite them to make the folder empty. The CLI recognizes empty directories of any name, hidden tool-metadata directories and files, Markdown instruction files, and default work/outputs directories, including their contents. It clones into a temporary folder, checks for file conflicts, and safely merges the repository into the current workspace. If actual application source or an existing .git is present, or repository files conflict with existing entries, stop and reconcile the workspace or use a new folder; never overwrite user work. In an existing repository with a remote, verify it matches the connected repository and branch; never overwrite unrelated files or force-push.
|
|
27
799
|
|
|
28
|
-
|
|
800
|
+
Initialize using App Id from the copied prompt and the current tool selection:
|
|
801
|
+
|
|
802
|
+
npx @backifydev/cli@latest init --app <app-id> --agent <current-tool>
|
|
803
|
+
|
|
804
|
+
For a tool without a built-in preset, replace --agent <current-tool> with --instruction-file <relative-path>. Read BACKIFY.md and the instruction file used by the current AI coding tool before changing application code. Create or update only instruction files used by that tool; never create files for other coding tools. Use --agent for a built-in tool preset or --instruction-file <relative-path> for the current tool's native instruction file, as described in the setup guide. Initialization installs this workflow alongside the persistent SDK instructions. Follow https://agent.backify.dev/v4 for instruction version 4; use the guide matching backify.json in an existing application. Do not silently upgrade its managed instruction version or overwrite instructions outside the managed block.
|
|
29
805
|
|
|
30
806
|
Run the following to discover the connected hosting target, repository, branch, reports, releases, and deployment failures:
|
|
31
807
|
|
|
32
|
-
npx @backifydev/cli@
|
|
808
|
+
npx @backifydev/cli@latest status
|
|
33
809
|
|
|
34
810
|
Connection and initialization may proceed without application requirements. Then ask what to build if none were supplied; never invent requirements or record this setup text as a user requirement.
|
|
35
811
|
|
|
@@ -37,10 +813,20 @@ Connection and initialization may proceed without application requirements. Then
|
|
|
37
813
|
|
|
38
814
|
For EVERY user request to build or modify this application, including the initial requirements supplied alongside or after setup, record only the user's own requirement text before changing application code. Submit the text through standard input to:
|
|
39
815
|
|
|
40
|
-
npx @backifydev/cli@
|
|
816
|
+
npx @backifydev/cli@latest prompt record --stdin --id <new-UUID> [--filename <basename> ...]
|
|
41
817
|
|
|
42
818
|
Record requests separately and in order. Generate a new UUID per request and reuse that UUID on retries. Add one --filename argument per attachment, using only its basename. Never send attachment bodies, extracted text, images, full paths, assistant responses, tool output, secrets, connection commands, or this setup/pairing block. Filename arguments are metadata only; never read attachment bodies to submit them. If recording fails, retry or report the blocker; never silently claim a request was recorded.
|
|
43
819
|
|
|
820
|
+
## Keep local source current
|
|
821
|
+
|
|
822
|
+
Automatically run the following before editing code for every new build or modification request, after recording the user requirement. Connecting an existing Git repository also runs this safe update automatically. A new clone already contains the connected branch's current source.
|
|
823
|
+
|
|
824
|
+
npx @backifydev/cli@latest pull
|
|
825
|
+
|
|
826
|
+
The CLI verifies the connected application, repository, branch, and repository root, fetches GitHub changes with a short-lived scoped credential, and fast-forwards only when the local working tree is clean and history has not diverged. It never switches branches, stashes, resets, rebases, discards files, or force-pushes automatically. If local or untracked changes would block an incoming update, or local commits diverge from GitHub, stop and explain the blocker; obtain explicit direction to reconcile it. Never continue editing against known stale source or claim a blocked pull succeeded. Already-current or locally-ahead source is left unchanged.
|
|
827
|
+
|
|
828
|
+
This is automatic at connection and at the start of each agent task, not a background watcher. Do not pull during ongoing edits or overwrite unrelated local work.
|
|
829
|
+
|
|
44
830
|
## Build for the connected hosting target
|
|
45
831
|
|
|
46
832
|
Inspect the framework, lockfile, scripts, configuration, and applicable repository instructions before editing. Preserve the existing framework. Use @backifydev/sdk for platform capabilities, verify API signatures against its installed types and https://docs.backify.dev/capabilities/, and do not directly provision external infrastructure.
|
|
@@ -53,11 +839,11 @@ Do not claim unsupported hosted server functions or SDK execution paths work. Re
|
|
|
53
839
|
|
|
54
840
|
Run:
|
|
55
841
|
|
|
56
|
-
npx @backifydev/cli@
|
|
842
|
+
npx @backifydev/cli@latest report --check
|
|
57
843
|
|
|
58
844
|
Fix relevant failures, then commit only application changes for this request using a meaningful message. Never commit credentials or unrelated user changes. Then run:
|
|
59
845
|
|
|
60
|
-
npx @backifydev/cli@
|
|
846
|
+
npx @backifydev/cli@latest ship
|
|
61
847
|
|
|
62
848
|
The CLI verifies the repository and branch, runs checks, pushes committed source using a short-lived repository-scoped credential, waits for the exact source's healthy preview, and publishes through existing Backify permissions and policy. It never stages or commits files, force-pushes, changes hosting, fabricates preview testing, or bypasses approval. Use --preview-only only when the user requests a preview.
|
|
63
849
|
|
|
@@ -67,9 +853,23 @@ These instructions are an explicit agent workflow, not a universal chat intercep
|
|
|
67
853
|
`;
|
|
68
854
|
|
|
69
855
|
// ../platform/dist/index.js
|
|
70
|
-
var INSTRUCTION_VERSION =
|
|
856
|
+
var INSTRUCTION_VERSION = 4;
|
|
71
857
|
var SDK_PACKAGE = "@backifydev/sdk";
|
|
72
858
|
var DOCS_URL = "https://docs.backify.dev";
|
|
859
|
+
var MAIL_LIMITS = Object.freeze({
|
|
860
|
+
monthlyAttempts: 25,
|
|
861
|
+
maximumRecipients: 50,
|
|
862
|
+
maximumAttachments: 10,
|
|
863
|
+
maximumAttachmentBytes: 10 * 1024 * 1024,
|
|
864
|
+
maximumBodyBytes: 256 * 1024,
|
|
865
|
+
maximumSubjectLength: 998,
|
|
866
|
+
maximumAddressLength: 254,
|
|
867
|
+
maximumAttachmentFilenameLength: 255,
|
|
868
|
+
maximumAttachmentContentTypeLength: 127,
|
|
869
|
+
maximumIdempotencyKeyLength: 128,
|
|
870
|
+
duplicateWindowMilliseconds: 5 * 60 * 1e3,
|
|
871
|
+
maximumRequestBytes: 16e6
|
|
872
|
+
});
|
|
73
873
|
var capability = (name, imp, description, stateful = false, provisioner = name) => ({ name, import: imp, version: 1, stateful, provisioner, docs: `${DOCS_URL}/capabilities/${name}`, description, destructiveRemovalRequiresApproval: stateful });
|
|
74
874
|
var CAPABILITIES = [
|
|
75
875
|
capability("auth", "auth", "Application users, organizations, roles, and permissions"),
|
|
@@ -78,7 +878,8 @@ var CAPABILITIES = [
|
|
|
78
878
|
capability("functions", "functions", "Server function declarations"),
|
|
79
879
|
capability("jobs", "jobs", "Reliable background work", true),
|
|
80
880
|
capability("scheduler", "jobs.schedule", "Scheduled job declarations"),
|
|
81
|
-
capability("events", "events", "
|
|
881
|
+
capability("events", "events", "Inbound webhooks and governed outbound HTTP", true),
|
|
882
|
+
{ ...capability("mail", "mail", "Server-only mail.send: to accepts an address or address array; 25 attempts per application per UTC month shared by all environments; 50 total To/CC/BCC recipients; 10 attachments totaling 10 MiB decoded; 256 KiB combined text/HTML; 998-character subject. Identical sends without an explicit idempotency key are deduplicated for a rolling 5 minutes. sensitive: true never stores original subjects or bodies. Read the mail capability guide and mail.limits before implementing sends.", true), limits: MAIL_LIMITS },
|
|
82
883
|
capability("secrets", "secrets", "Server-side secret retrieval", true),
|
|
83
884
|
capability("http", "http", "Governed outbound HTTP"),
|
|
84
885
|
capability("ai", "ai", "Provider-independent generative AI"),
|
|
@@ -125,7 +926,7 @@ Run relevant tests, typechecking, lint, and builds using the repository's script
|
|
|
125
926
|
|
|
126
927
|
## Connected application delivery
|
|
127
928
|
|
|
128
|
-
For connected applications, follow \`BACKIFY
|
|
929
|
+
For connected applications, follow \`BACKIFY.md\` and https://agent.backify.dev/v${INSTRUCTION_VERSION}/delivery.md before changing application code. Record every user build or modification request, including initial requirements, with attachment filenames only; never submit attachment contents or setup credentials. Verify checks and publish through the connected CLI workflow without bypassing testing, approval, or coding-tool permissions. Report only verified deployment URLs.
|
|
129
930
|
|
|
130
931
|
## Instruction maintenance
|
|
131
932
|
|
|
@@ -171,68 +972,104 @@ function validateConfig(value) {
|
|
|
171
972
|
errors.push("appId must use the app_<id> format");
|
|
172
973
|
if (!Number.isInteger(x.instructionVersion) || Number(x.instructionVersion) < 1)
|
|
173
974
|
errors.push("instructionVersion must be a positive integer");
|
|
975
|
+
if (x.agent !== void 0 && !["codex", "claude", "copilot", "gemini", "custom"].includes(x.agent))
|
|
976
|
+
errors.push("agent must be codex, claude, copilot, gemini, or custom");
|
|
977
|
+
if (x.instructionFile !== void 0 && (typeof x.instructionFile !== "string" || !x.instructionFile.trim()))
|
|
978
|
+
errors.push("instructionFile must be a nonempty relative path");
|
|
174
979
|
if (x.instructions?.preferBackifyCapabilities !== true)
|
|
175
980
|
errors.push("instructions.preferBackifyCapabilities must be true");
|
|
176
981
|
if (x.instructions?.allowDirectCloudInfrastructure !== false)
|
|
177
982
|
errors.push("instructions.allowDirectCloudInfrastructure must be false");
|
|
178
983
|
return errors;
|
|
179
984
|
}
|
|
180
|
-
var BACKIFY_SCHEMA = { $schema: "https://json-schema.org/draft/2020-12/schema", $id: `${DOCS_URL}/schema/backify.json`, type: "object", additionalProperties: false, required: ["$schema", "platform", "sdk", "appId", "instructionVersion", "docs", "instructions"], properties: { $schema: { const: `${DOCS_URL}/schema/backify.json` }, platform: { const: "backify" }, sdk: { const: SDK_PACKAGE }, appId: { type: "string", pattern: "^app_[A-Za-z0-9_-]+$" }, instructionVersion: { type: "integer", minimum: 1 }, docs: { type: "string", format: "uri" }, instructions: { type: "object", additionalProperties: false, required: ["preferBackifyCapabilities", "allowDirectCloudInfrastructure"], properties: { preferBackifyCapabilities: { const: true }, allowDirectCloudInfrastructure: { const: false } } } } };
|
|
985
|
+
var BACKIFY_SCHEMA = { $schema: "https://json-schema.org/draft/2020-12/schema", $id: `${DOCS_URL}/schema/backify.json`, type: "object", additionalProperties: false, required: ["$schema", "platform", "sdk", "appId", "instructionVersion", "docs", "instructions"], properties: { $schema: { const: `${DOCS_URL}/schema/backify.json` }, platform: { const: "backify" }, sdk: { const: SDK_PACKAGE }, appId: { type: "string", pattern: "^app_[A-Za-z0-9_-]+$" }, instructionVersion: { type: "integer", minimum: 1 }, agent: { enum: ["codex", "claude", "copilot", "gemini", "custom"] }, instructionFile: { type: "string", minLength: 1 }, docs: { type: "string", format: "uri" }, instructions: { type: "object", additionalProperties: false, required: ["preferBackifyCapabilities", "allowDirectCloudInfrastructure"], properties: { preferBackifyCapabilities: { const: true }, allowDirectCloudInfrastructure: { const: false } } } } };
|
|
181
986
|
|
|
182
987
|
// src/delivery.ts
|
|
183
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
184
|
-
import { join } from "node:path";
|
|
988
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
989
|
+
import { dirname as dirname2, join, relative as relativePath } from "node:path";
|
|
185
990
|
import { createHash } from "node:crypto";
|
|
186
|
-
var previousGeneratedWorkflowHashes = /* @__PURE__ */ new Set(["6eb280ae7bdb14c390011686c41400f59c023304c3015d8440b7e80aaafa1c11", "545e03a1d5b996ade179e0e60ed5c86accdadc1982c1c25efd094e34f72f47ee"]);
|
|
991
|
+
var previousGeneratedWorkflowHashes = /* @__PURE__ */ new Set(["578dfb4c771c623fd04454e8a604efd701d5563d11e11191324862369bd24718", "6eb280ae7bdb14c390011686c41400f59c023304c3015d8440b7e80aaafa1c11", "545e03a1d5b996ade179e0e60ed5c86accdadc1982c1c25efd094e34f72f47ee"]);
|
|
187
992
|
function validateDeliveryInstructions(root) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
993
|
+
for (const filename of ["BACKIFY.md", "BACKIFY-WORKFLOW.md"]) {
|
|
994
|
+
const path = join(root, filename);
|
|
995
|
+
if (existsSync2(path)) {
|
|
996
|
+
const existing = readFileSync(path, "utf8").replace(/\r\n/g, "\n");
|
|
997
|
+
if (existing !== deliveryInstructions && !previousGeneratedWorkflowHashes.has(createHash("sha256").update(existing).digest("hex"))) throw new Error(filename + " contains different instructions. Review it before initializing; it will not be overwritten.");
|
|
998
|
+
}
|
|
192
999
|
}
|
|
193
1000
|
}
|
|
194
1001
|
function installDeliveryInstructions(root, instructionFiles2) {
|
|
195
1002
|
validateDeliveryInstructions(root);
|
|
196
|
-
|
|
197
|
-
writeFileSync(path, deliveryInstructions);
|
|
1003
|
+
writeFileSync2(join(root, "BACKIFY.md"), deliveryInstructions);
|
|
198
1004
|
for (const relative of instructionFiles2) {
|
|
199
1005
|
const instructionPath = join(root, relative), content = readFileSync(instructionPath, "utf8");
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
1006
|
+
const link = relativePath(dirname2(instructionPath), join(root, "BACKIFY.md")).replaceAll("\\", "/");
|
|
1007
|
+
const legacyLink = relativePath(dirname2(instructionPath), join(root, "BACKIFY-WORKFLOW.md")).replaceAll("\\", "/");
|
|
1008
|
+
const legacy = "For application delivery and recording each user request, follow [BACKIFY-WORKFLOW.md](" + legacyLink + ").";
|
|
1009
|
+
const guidance = "For application delivery and recording each user request, follow [BACKIFY.md](" + link + ").";
|
|
1010
|
+
if (content.includes(legacy)) writeFileSync2(instructionPath, content.replace(legacy, guidance));
|
|
1011
|
+
else if (!content.includes("## Backify delivery")) writeFileSync2(instructionPath, content.trimEnd() + "\n\n## Backify delivery\n\n" + guidance + "\n");
|
|
203
1012
|
}
|
|
204
1013
|
}
|
|
205
1014
|
|
|
206
1015
|
// src/setup.ts
|
|
207
|
-
var instructionFiles = ["AGENTS.md"
|
|
1016
|
+
var instructionFiles = ["AGENTS.md"];
|
|
1017
|
+
var agentInstructionFiles = { codex: "AGENTS.md", claude: "CLAUDE.md", copilot: join2(".github", "copilot-instructions.md"), gemini: "GEMINI.md" };
|
|
1018
|
+
function instructionSelection(root, agent, instructionFile) {
|
|
1019
|
+
const configPath2 = join2(root, "backify.json"), configured = existsSync3(configPath2) ? JSON.parse(readFileSync2(configPath2, "utf8")) : {};
|
|
1020
|
+
const custom = instructionFile ?? (agent === void 0 ? configured.instructionFile : void 0);
|
|
1021
|
+
const selected = instructionFile !== void 0 ? "custom" : agent ?? configured.agent ?? "codex";
|
|
1022
|
+
if (typeof selected !== "string" || selected !== "custom" && !Object.hasOwn(agentInstructionFiles, selected)) throw new Error("Select the current tool with --agent or --instruction-file <relative-path>.");
|
|
1023
|
+
const filename = custom ?? agentInstructionFiles[selected];
|
|
1024
|
+
if (typeof filename !== "string" || !filename.trim()) throw new Error("Select the current tool with --agent codex, claude, copilot, or gemini, or --instruction-file <relative-path> for any other tool.");
|
|
1025
|
+
const normalized = filename.replaceAll("\\", "/"), parts = normalized.split("/");
|
|
1026
|
+
if (isAbsolute(filename) || /^[A-Za-z]:/.test(filename) || parts.some((part) => !part || part === "." || part === ".." || part.toLowerCase() === ".git") || ["backify.md", "backify-workflow.md", "backify.json", "package.json", "package-lock.json"].includes(normalized.toLowerCase())) throw new Error("Instruction file must be a relative tool-instruction path inside the project, not Git metadata or a Backify configuration file.");
|
|
1027
|
+
for (let index = 1; index <= parts.length; index++) {
|
|
1028
|
+
const entry = join2(root, ...parts.slice(0, index));
|
|
1029
|
+
try {
|
|
1030
|
+
const metadata = lstatSync(entry);
|
|
1031
|
+
if (metadata.isSymbolicLink() || index < parts.length && !metadata.isDirectory() || index === parts.length && !metadata.isFile()) throw new Error("Instruction file path cannot traverse symlinks or replace a directory.");
|
|
1032
|
+
} catch (reason) {
|
|
1033
|
+
if (reason.code !== "ENOENT") throw reason;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return { agent: selected, instructionFile: normalized, files: [normalized] };
|
|
1037
|
+
}
|
|
1038
|
+
function selectedInstructionFiles(root = process.cwd(), agent, instructionFile) {
|
|
1039
|
+
return instructionSelection(root, agent, instructionFile).files;
|
|
1040
|
+
}
|
|
1041
|
+
function isToolWorkspaceEntry(entry, root = process.cwd()) {
|
|
1042
|
+
if (entry.name.toLowerCase() === ".git" || entry.name.toLowerCase() === ".env" || entry.name.toLowerCase().startsWith(".env.")) return false;
|
|
1043
|
+
return entry.isDirectory() && (entry.name.startsWith(".") || ["work", "outputs"].includes(entry.name) || readdirSync(join2(root, entry.name)).length === 0) || entry.isFile() && (entry.name.startsWith(".") || /\.(md|mdc)$/i.test(entry.name));
|
|
1044
|
+
}
|
|
208
1045
|
function detectPackageManager(root = process.cwd()) {
|
|
209
|
-
for (const [file, name] of [["pnpm-lock.yaml", "pnpm"], ["yarn.lock", "yarn"], ["bun.lockb", "bun"], ["bun.lock", "bun"], ["package-lock.json", "npm"]]) if (
|
|
1046
|
+
for (const [file, name] of [["pnpm-lock.yaml", "pnpm"], ["yarn.lock", "yarn"], ["bun.lockb", "bun"], ["bun.lock", "bun"], ["package-lock.json", "npm"]]) if (existsSync3(join2(root, file))) return name;
|
|
210
1047
|
return "npm";
|
|
211
1048
|
}
|
|
212
|
-
function updateInstructions(root = process.cwd()) {
|
|
213
|
-
const updates =
|
|
1049
|
+
function updateInstructions(root = process.cwd(), agent, instructionFile) {
|
|
1050
|
+
const updates = selectedInstructionFiles(root, agent, instructionFile).map((relative) => {
|
|
214
1051
|
const path = join2(root, relative);
|
|
215
|
-
return { path, content: updateManagedInstructions(
|
|
1052
|
+
return { path, content: updateManagedInstructions(existsSync3(path) ? readFileSync2(path, "utf8") : "") };
|
|
216
1053
|
});
|
|
217
1054
|
for (const { path, content } of updates) {
|
|
218
|
-
|
|
219
|
-
|
|
1055
|
+
mkdirSync2(dirname3(path), { recursive: true });
|
|
1056
|
+
writeFileSync3(path, content);
|
|
220
1057
|
}
|
|
221
1058
|
}
|
|
222
|
-
function synchronize(root = process.cwd()) {
|
|
1059
|
+
function synchronize(root = process.cwd(), agent, instructionFile) {
|
|
223
1060
|
const path = join2(root, "backify.json");
|
|
224
|
-
if (!
|
|
1061
|
+
if (!existsSync3(path)) throw new Error("backify.json is missing; run backify init --app app_xxxxx");
|
|
225
1062
|
const value = JSON.parse(readFileSync2(path, "utf8")), issues = validateConfig(value);
|
|
226
1063
|
if (issues.length) throw new Error(issues.join("; "));
|
|
227
1064
|
if (value.instructionVersion > INSTRUCTION_VERSION) throw new Error("This app uses newer instructions. Install a matching or newer CLI before syncing.");
|
|
1065
|
+
const selected = instructionSelection(root, agent, instructionFile);
|
|
228
1066
|
validateDeliveryInstructions(root);
|
|
229
|
-
updateInstructions(root);
|
|
230
|
-
installDeliveryInstructions(root,
|
|
1067
|
+
updateInstructions(root, selected.agent, selected.instructionFile);
|
|
1068
|
+
installDeliveryInstructions(root, selected.files);
|
|
1069
|
+
value.agent = selected.agent;
|
|
1070
|
+
value.instructionFile = selected.instructionFile;
|
|
231
1071
|
value.instructionVersion = INSTRUCTION_VERSION;
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
function writeConfig(appId, root = process.cwd()) {
|
|
235
|
-
writeFileSync2(join2(root, "backify.json"), JSON.stringify(createConfig(appId), null, 2) + "\n");
|
|
1072
|
+
writeFileSync3(path, JSON.stringify(value, null, 2) + "\n");
|
|
236
1073
|
}
|
|
237
1074
|
function sdkInstalled(root = process.cwd()) {
|
|
238
1075
|
try {
|
|
@@ -249,21 +1086,25 @@ function installSdk(root = process.cwd()) {
|
|
|
249
1086
|
}
|
|
250
1087
|
function ensurePackageManifest(root) {
|
|
251
1088
|
const path = join2(root, "package.json");
|
|
252
|
-
if (
|
|
253
|
-
const setupFiles = /* @__PURE__ */ new Set([".git", ".gitignore", ".github", "AGENTS.md", "CLAUDE.md", "README.md", "LICENSE", "backify.json"]);
|
|
254
|
-
if (readdirSync(root).some((
|
|
255
|
-
const name = basename(
|
|
256
|
-
|
|
1089
|
+
if (existsSync3(path)) return;
|
|
1090
|
+
const setupFiles = /* @__PURE__ */ new Set([".git", ".gitignore", ".github", "AGENTS.md", "CLAUDE.md", "GEMINI.md", "BACKIFY.md", "BACKIFY-WORKFLOW.md", "README.md", "LICENSE", "backify.json"]);
|
|
1091
|
+
if (readdirSync(root, { withFileTypes: true }).some((entry) => !setupFiles.has(entry.name) && !isToolWorkspaceEntry(entry, root))) throw new Error("package.json is missing. Run backify init from the existing application's JavaScript/TypeScript package directory, or start in an empty folder. See https://agent.backify.dev/");
|
|
1092
|
+
const name = basename(resolve2(root)).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "backify-app";
|
|
1093
|
+
writeFileSync3(path, JSON.stringify({ name, version: "0.0.0", private: true, type: "module" }, null, 2) + "\n", { flag: "wx" });
|
|
257
1094
|
}
|
|
258
|
-
function initialize(appId, root = process.cwd(), install = true) {
|
|
1095
|
+
function initialize(appId, root = process.cwd(), install = true, agent, instructionFile) {
|
|
259
1096
|
if (!/^app_[A-Za-z0-9_-]+$/.test(appId)) throw new Error("Provide an application ID using --app app_xxxxx");
|
|
1097
|
+
const selected = instructionSelection(root, agent, instructionFile), files = selected.files;
|
|
1098
|
+
validateDeliveryInstructions(root);
|
|
1099
|
+
for (const relative of files) if (existsSync3(join2(root, relative))) updateManagedInstructions(readFileSync2(join2(root, relative), "utf8"));
|
|
260
1100
|
ensurePackageManifest(root);
|
|
261
1101
|
if (install) installSdk(root);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
1102
|
+
const configPath2 = join2(root, "backify.json"), existing = existsSync3(configPath2) ? JSON.parse(readFileSync2(configPath2, "utf8")) : {};
|
|
1103
|
+
writeFileSync3(configPath2, JSON.stringify({ ...existing, ...createConfig(appId), agent: selected.agent, instructionFile: selected.instructionFile }, null, 2) + "\n");
|
|
1104
|
+
updateInstructions(root, selected.agent, selected.instructionFile);
|
|
1105
|
+
installDeliveryInstructions(root, files);
|
|
265
1106
|
}
|
|
266
|
-
function doctor(root = process.cwd()) {
|
|
1107
|
+
function doctor(root = process.cwd(), agent, instructionFile) {
|
|
267
1108
|
const issues = [], warnings = [];
|
|
268
1109
|
if (!sdkInstalled(root)) issues.push(`${SDK_PACKAGE} is not installed`);
|
|
269
1110
|
let config;
|
|
@@ -274,9 +1115,15 @@ function doctor(root = process.cwd()) {
|
|
|
274
1115
|
issues.push("backify.json is missing or invalid JSON");
|
|
275
1116
|
}
|
|
276
1117
|
if (config && config.instructionVersion !== INSTRUCTION_VERSION) issues.push(`Repository instruction version ${config.instructionVersion}; CLI version ${INSTRUCTION_VERSION}. Use the matching CLI or run backify sync to upgrade.`);
|
|
277
|
-
|
|
1118
|
+
let files = instructionFiles;
|
|
1119
|
+
try {
|
|
1120
|
+
files = selectedInstructionFiles(root, agent, instructionFile);
|
|
1121
|
+
} catch (reason) {
|
|
1122
|
+
issues.push(reason instanceof Error ? reason.message : String(reason));
|
|
1123
|
+
}
|
|
1124
|
+
for (const relative of files) {
|
|
278
1125
|
const path = join2(root, relative);
|
|
279
|
-
if (!
|
|
1126
|
+
if (!existsSync3(path)) {
|
|
280
1127
|
issues.push(`${relative} is missing`);
|
|
281
1128
|
continue;
|
|
282
1129
|
}
|
|
@@ -300,7 +1147,7 @@ function applicationGuid(appId) {
|
|
|
300
1147
|
return [value.slice(0, 8), value.slice(8, 12), value.slice(12, 16), value.slice(16, 20), value.slice(20)].join("-");
|
|
301
1148
|
}
|
|
302
1149
|
function projectApplication(root = process.cwd()) {
|
|
303
|
-
if (!
|
|
1150
|
+
if (!existsSync4(join3(root, "backify.json"))) throw new Error("Run backify connect --app <application-id>, then backify init.");
|
|
304
1151
|
return JSON.parse(readFileSync3(join3(root, "backify.json"), "utf8")).appId;
|
|
305
1152
|
}
|
|
306
1153
|
function apiAddress(value) {
|
|
@@ -329,7 +1176,7 @@ function apiClient(session, transport = fetch) {
|
|
|
329
1176
|
function saveUserConfig(path, config) {
|
|
330
1177
|
const temporary = path + "." + randomUUID() + ".tmp";
|
|
331
1178
|
try {
|
|
332
|
-
|
|
1179
|
+
writeFileSync4(temporary, JSON.stringify(config, null, 2) + "\n", { mode: 384, flag: "wx" });
|
|
333
1180
|
if (process.platform === "win32") {
|
|
334
1181
|
const account = [process.env.USERDOMAIN, process.env.USERNAME].filter(Boolean).join("\\");
|
|
335
1182
|
if (!account) throw new Error("Cannot identify the account to protect CLI credentials.");
|
|
@@ -355,13 +1202,57 @@ function gitEnvironment(repository, token) {
|
|
|
355
1202
|
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)) throw new Error("Invalid repository.");
|
|
356
1203
|
return { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_CONFIG_COUNT: "3", GIT_CONFIG_KEY_0: "http.https://github.com/" + repository + ".git.extraheader", GIT_CONFIG_VALUE_0: "Authorization: Basic " + Buffer.from("x-access-token:" + token).toString("base64"), GIT_CONFIG_KEY_1: "credential.helper", GIT_CONFIG_VALUE_1: "", GIT_CONFIG_KEY_2: "http.followRedirects", GIT_CONFIG_VALUE_2: "false" };
|
|
357
1204
|
}
|
|
1205
|
+
function validateCloneMerge(source, target) {
|
|
1206
|
+
for (const entry of readdirSync2(source, { withFileTypes: true })) {
|
|
1207
|
+
const destination = join3(target, entry.name);
|
|
1208
|
+
let existing;
|
|
1209
|
+
try {
|
|
1210
|
+
existing = lstatSync2(destination);
|
|
1211
|
+
} catch (reason) {
|
|
1212
|
+
if (reason.code === "ENOENT") continue;
|
|
1213
|
+
throw reason;
|
|
1214
|
+
}
|
|
1215
|
+
if (entry.isDirectory() && existing.isDirectory() && !existing.isSymbolicLink()) validateCloneMerge(join3(source, entry.name), destination);
|
|
1216
|
+
else throw new Error("Clone conflicts with existing workspace entry: " + destination + ". Existing files are never overwritten; reconcile the conflict or use a new folder.");
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
358
1219
|
async function cloneProject(call2, appId, root = process.cwd()) {
|
|
359
1220
|
const status = await call2("/apps/" + applicationGuid(appId) + "/developer");
|
|
360
1221
|
if (!status.repository || !status.branch || !status.workflowReady) throw new Error("Connect the repository in Backify and wait for workflow setup.");
|
|
361
|
-
if (readdirSync2(root).
|
|
1222
|
+
if (readdirSync2(root, { withFileTypes: true }).some((entry) => !isToolWorkspaceEntry(entry, root))) throw new Error("--clone requires an empty directory or a workspace containing only AI tool metadata and default work/outputs directories. Existing application files and Git repositories are never overwritten.");
|
|
362
1223
|
const credential = await call2("/apps/" + applicationGuid(appId) + "/developer/git-credential", { method: "POST" });
|
|
363
1224
|
if (credential.repository.toLowerCase() !== status.repository.toLowerCase()) throw new Error("Repository changed. Run connect again.");
|
|
364
|
-
|
|
1225
|
+
const staging = mkdtempSync(join3(dirname4(resolve3(root)), ".backify-clone-"));
|
|
1226
|
+
try {
|
|
1227
|
+
git(["clone", "--single-branch", "--branch", status.branch, "--", "https://github.com/" + status.repository + ".git", "."], staging, gitEnvironment(status.repository, credential.token));
|
|
1228
|
+
validateCloneMerge(staging, root);
|
|
1229
|
+
for (const entry of readdirSync2(staging)) cpSync(join3(staging, entry), join3(root, entry), { recursive: true, force: false, errorOnExist: true, dereference: false });
|
|
1230
|
+
} finally {
|
|
1231
|
+
if (dirname4(staging) !== dirname4(resolve3(root)) || !staging.startsWith(join3(dirname4(resolve3(root)), ".backify-clone-"))) throw new Error("Refusing to clean up an unexpected clone staging path.");
|
|
1232
|
+
rmSync(staging, { recursive: true, force: true });
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
async function pullProject(call2, appId, root = process.cwd()) {
|
|
1236
|
+
if (existsSync4(join3(root, "backify.json")) && applicationGuid(projectApplication(root)) !== applicationGuid(appId)) throw new Error("Local application ID does not match the connected application.");
|
|
1237
|
+
const prefix = "/apps/" + applicationGuid(appId);
|
|
1238
|
+
const status = await call2(prefix + "/developer");
|
|
1239
|
+
if (!status.repository || !status.branch) throw new Error("Connect the repository and branch in Backify before pulling.");
|
|
1240
|
+
if (resolve3(git(["rev-parse", "--show-toplevel"], root)) !== resolve3(root)) throw new Error("Run pull from the connected repository root.");
|
|
1241
|
+
if (repositoryName(git(["remote", "get-url", "origin"], root)) !== status.repository.toLowerCase()) throw new Error("Local origin does not match the repository connected in Backify.");
|
|
1242
|
+
if (git(["branch", "--show-current"], root) !== status.branch) throw new Error("Local branch does not match the branch connected in Backify. The CLI never switches branches automatically.");
|
|
1243
|
+
git(["check-ref-format", "--branch", status.branch], root);
|
|
1244
|
+
const credential = await call2(prefix + "/developer/git-credential", { method: "POST" });
|
|
1245
|
+
if (credential.repository.toLowerCase() !== status.repository.toLowerCase()) throw new Error("Repository changed; reconnect before pulling.");
|
|
1246
|
+
git(["fetch", "--no-tags", "--", "https://github.com/" + status.repository + ".git", "refs/heads/" + status.branch + ":refs/remotes/origin/" + status.branch], root, gitEnvironment(status.repository, credential.token));
|
|
1247
|
+
const remoteCommit = git(["rev-parse", "FETCH_HEAD"], root);
|
|
1248
|
+
const counts = git(["rev-list", "--left-right", "--count", "HEAD..." + remoteCommit], root).split(/\s+/).map(Number);
|
|
1249
|
+
if (counts.length !== 2 || counts.some((count) => !Number.isSafeInteger(count) || count < 0)) throw new Error("Could not compare local and remote history.");
|
|
1250
|
+
const [ahead, behind] = counts;
|
|
1251
|
+
if (!behind) return { status: "up-to-date", ahead, behind, commit: git(["rev-parse", "HEAD"], root) };
|
|
1252
|
+
if (ahead) return { status: "blocked", reason: "Local and GitHub history have diverged. Review and reconcile them explicitly; no rebase, reset, or force-push was performed.", ahead, behind };
|
|
1253
|
+
if (git(["status", "--porcelain"], root)) return { status: "blocked", reason: "Local changes or untracked files are present. Commit, ignore, or otherwise resolve them explicitly before updating; nothing was stashed or overwritten.", ahead, behind };
|
|
1254
|
+
git(["merge", "--ff-only", "--", remoteCommit], root);
|
|
1255
|
+
return { status: "updated", ahead: 0, behind: 0, commit: git(["rev-parse", "HEAD"], root) };
|
|
365
1256
|
}
|
|
366
1257
|
async function readPrompt(input) {
|
|
367
1258
|
const chunks = [];
|
|
@@ -404,23 +1295,23 @@ function localReport(runChecks, root = process.cwd()) {
|
|
|
404
1295
|
dirty = Boolean(git(["status", "--porcelain"], root));
|
|
405
1296
|
} catch {
|
|
406
1297
|
}
|
|
407
|
-
const outputDirectory = ["dist", "build", "out", "."].find((directory) =>
|
|
408
|
-
return { framework, sdkVersion: dependencies["@backifydev/sdk"] ?? null, branch, commitSha, dirty, buildCommand: pkg.scripts?.build ? manager + " run build" : null, outputDirectory, hasDockerfile:
|
|
1298
|
+
const outputDirectory = ["dist", "build", "out", "."].find((directory) => existsSync4(join3(root, directory, "index.html"))) ?? null;
|
|
1299
|
+
return { framework, sdkVersion: dependencies["@backifydev/sdk"] ?? null, branch, commitSha, dirty, buildCommand: pkg.scripts?.build ? manager + " run build" : null, outputDirectory, hasDockerfile: existsSync4(join3(root, "Dockerfile")), checks };
|
|
409
1300
|
}
|
|
410
1301
|
function matchesSource(release, commit) {
|
|
411
1302
|
return release?.commitSha === commit || release?.sourceCommitSha === commit;
|
|
412
1303
|
}
|
|
413
1304
|
async function waitForPreview(call2, prefix, commit, options = {}) {
|
|
414
1305
|
const deadline = Date.now() + (options.timeoutMs ?? 20 * 6e4);
|
|
415
|
-
const sleep = options.sleep ?? ((delay) => new Promise((
|
|
1306
|
+
const sleep = options.sleep ?? ((delay) => new Promise((resolve4) => setTimeout(resolve4, delay)));
|
|
416
1307
|
do {
|
|
417
1308
|
const deployments = await call2(prefix + "/deployments");
|
|
418
1309
|
const matching = deployments.find((release) => release.kind === "preview" && matchesSource(release, commit) && !options.previousDeploymentIds?.includes(release.id));
|
|
419
1310
|
if (matching?.status === "failed") throw new Error("Deployment of this source failed. Run backify status and inspect its deployment steps.");
|
|
420
1311
|
const overview = await call2(prefix + "/releases");
|
|
421
1312
|
if (matchesSource(overview.preview, commit) && overview.preview?.status === "succeeded" && overview.preview.healthResult === "healthy") return overview;
|
|
422
|
-
const
|
|
423
|
-
if ((options.previousBuildRunId === void 0 ||
|
|
1313
|
+
const build2 = await call2(prefix + "/developer/build?commitSha=" + commit);
|
|
1314
|
+
if ((options.previousBuildRunId === void 0 || build2.runId !== options.previousBuildRunId) && ["failure", "cancelled", "timed_out", "action_required", "startup_failure"].includes(build2.conclusion ?? "")) throw new Error("GitHub build " + build2.conclusion + ". " + (build2.url ?? "Run backify status for details."));
|
|
424
1315
|
await sleep(options.intervalMs ?? 4e3);
|
|
425
1316
|
} while (Date.now() < deadline);
|
|
426
1317
|
throw new Error("Timed out waiting for this commit's healthy preview. Run backify status; no production release was requested.");
|
|
@@ -432,7 +1323,7 @@ async function ship(call2, appId, options = {}) {
|
|
|
432
1323
|
if (!doctor(root).valid) throw new Error("Run backify doctor and fix project setup before shipping.");
|
|
433
1324
|
if (applicationGuid(projectApplication(root)) !== applicationGuid(appId)) throw new Error("Local application ID does not match the application being shipped.");
|
|
434
1325
|
const actualRoot = git(["rev-parse", "--show-toplevel"], root);
|
|
435
|
-
if (
|
|
1326
|
+
if (resolve3(actualRoot).toLowerCase() !== resolve3(root).toLowerCase()) throw new Error("Shipping currently requires the application at the repository root.");
|
|
436
1327
|
const origin = git(["remote", "get-url", "origin"], root);
|
|
437
1328
|
const pushOrigin = git(["remote", "get-url", "--push", "origin"], root);
|
|
438
1329
|
if (repositoryName(origin) !== status.repository.toLowerCase() || repositoryName(pushOrigin) !== status.repository.toLowerCase()) throw new Error("Local repository does not match this Backify application.");
|
|
@@ -482,24 +1373,24 @@ async function publishPreview(call2, prefix, overview, options = {}) {
|
|
|
482
1373
|
if (releases.live?.previewDeploymentId !== preview.id || releases.live.status !== "succeeded" || releases.live.healthResult !== "healthy") throw new Error("Production did not activate this healthy release. Run backify status.");
|
|
483
1374
|
return { status: "live", url: releases.live.url };
|
|
484
1375
|
}
|
|
485
|
-
await new Promise((
|
|
1376
|
+
await new Promise((resolve4) => setTimeout(resolve4, 4e3));
|
|
486
1377
|
} while (Date.now() < deadline);
|
|
487
1378
|
throw new Error("Publication is still pending. Run backify status; deployment success has not been verified.");
|
|
488
1379
|
}
|
|
489
1380
|
|
|
490
1381
|
// src/index.ts
|
|
491
|
-
import { readFileSync as readFileSync4, existsSync as
|
|
1382
|
+
import { readFileSync as readFileSync4, existsSync as existsSync5, rmSync as rmSync2 } from "node:fs";
|
|
492
1383
|
import { homedir } from "node:os";
|
|
493
1384
|
import { join as join4 } from "node:path";
|
|
494
1385
|
import { randomBytes } from "node:crypto";
|
|
495
1386
|
import { createServer } from "node:http";
|
|
496
1387
|
import { spawn } from "node:child_process";
|
|
497
1388
|
var configPath = join4(homedir(), ".backify.json");
|
|
498
|
-
var userConfig =
|
|
1389
|
+
var userConfig = existsSync5(configPath) ? JSON.parse(readFileSync4(configPath, "utf8")) : {};
|
|
499
1390
|
var [command, ...args] = process.argv.slice(2);
|
|
500
1391
|
async function call(path, init) {
|
|
501
1392
|
let appId = option("--app");
|
|
502
|
-
if (!appId &&
|
|
1393
|
+
if (!appId && existsSync5(join4(process.cwd(), "backify.json"))) appId = projectApplication();
|
|
503
1394
|
const session = appId ? userConfig.sessions?.["app_" + applicationGuid(appId).replaceAll("-", "")] : void 0;
|
|
504
1395
|
return apiClient(session ?? { token: userConfig.token ?? "", organizationId: userConfig.organizationId ?? "", apiUrl: process.env.BACKIFY_API_URL ?? userConfig.apiUrl ?? "https://api.backify.dev/api" })(path, init);
|
|
505
1396
|
}
|
|
@@ -544,7 +1435,7 @@ async function browserLogin() {
|
|
|
544
1435
|
});
|
|
545
1436
|
let resolveLogin = () => {
|
|
546
1437
|
};
|
|
547
|
-
const completed = new Promise((
|
|
1438
|
+
const completed = new Promise((resolve4) => resolveLogin = resolve4);
|
|
548
1439
|
server.listen(0, "127.0.0.1", () => {
|
|
549
1440
|
const address = server.address();
|
|
550
1441
|
if (!address || typeof address === "string") throw new Error("Could not start local login callback");
|
|
@@ -570,16 +1461,31 @@ async function browserLogin() {
|
|
|
570
1461
|
}
|
|
571
1462
|
async function main() {
|
|
572
1463
|
switch (command) {
|
|
1464
|
+
case "functions": {
|
|
1465
|
+
if (args[0] === "package") {
|
|
1466
|
+
const entry = option("--entry");
|
|
1467
|
+
if (!entry) throw new Error("Use backify functions package --entry <functions.ts> [--out functions.zip]");
|
|
1468
|
+
console.log(await packageFunctions(entry, option("--out") ?? "functions.zip"));
|
|
1469
|
+
} else if (args[0] === "deploy") {
|
|
1470
|
+
const appId = applicationGuid(option("--app") ?? projectApplication());
|
|
1471
|
+
const environmentId = option("--environment");
|
|
1472
|
+
const packagePath = option("--package");
|
|
1473
|
+
if (!environmentId || !packagePath || !args.includes("--confirm")) throw new Error("Use backify functions deploy --environment <environment-id> --package <functions.zip> --confirm. This replaces the complete function project.");
|
|
1474
|
+
await call("/apps/" + appId + "/functions/environments/" + applicationGuid(environmentId) + "/deploy?confirm=true", { method: "POST", headers: { "content-type": "application/zip" }, body: new Uint8Array(readFileSync4(packagePath)) });
|
|
1475
|
+
console.log("Functions deployed.");
|
|
1476
|
+
} else throw new Error("Use backify functions package or backify functions deploy");
|
|
1477
|
+
break;
|
|
1478
|
+
}
|
|
573
1479
|
case "init":
|
|
574
|
-
initialize(option("--app") ?? args.find((value) => !value.startsWith("-")) ?? "");
|
|
1480
|
+
initialize(option("--app") ?? args.find((value) => !value.startsWith("-")) ?? "", process.cwd(), true, option("--agent"), option("--instruction-file"));
|
|
575
1481
|
console.log("Backify initialized. SDK, delivery instructions, and prompt history guidance are ready.");
|
|
576
1482
|
break;
|
|
577
1483
|
case "sync":
|
|
578
|
-
synchronize();
|
|
1484
|
+
synchronize(process.cwd(), option("--agent"), option("--instruction-file"));
|
|
579
1485
|
console.log("Backify instructions synchronized to version " + INSTRUCTION_VERSION);
|
|
580
1486
|
break;
|
|
581
1487
|
case "doctor": {
|
|
582
|
-
const result = doctor();
|
|
1488
|
+
const result = doctor(process.cwd(), option("--agent"), option("--instruction-file"));
|
|
583
1489
|
console.log(JSON.stringify(result, null, 2));
|
|
584
1490
|
if (!result.valid) process.exitCode = 1;
|
|
585
1491
|
break;
|
|
@@ -617,6 +1523,11 @@ async function main() {
|
|
|
617
1523
|
userConfig.sessions[key] = session;
|
|
618
1524
|
saveUserConfig(configPath, userConfig);
|
|
619
1525
|
if (args.includes("--clone")) await cloneProject(client, appId);
|
|
1526
|
+
else if (existsSync5(join4(process.cwd(), ".git"))) {
|
|
1527
|
+
const update = await pullProject(client, appId);
|
|
1528
|
+
console.log(JSON.stringify(update, null, 2));
|
|
1529
|
+
if (update.status === "blocked") throw new Error(update.reason);
|
|
1530
|
+
}
|
|
620
1531
|
console.log(JSON.stringify(await client("/apps/" + applicationGuid(appId) + "/developer"), null, 2));
|
|
621
1532
|
break;
|
|
622
1533
|
}
|
|
@@ -626,6 +1537,12 @@ async function main() {
|
|
|
626
1537
|
saveUserConfig(configPath, userConfig);
|
|
627
1538
|
console.log("Application CLI sessions revoked.");
|
|
628
1539
|
break;
|
|
1540
|
+
case "pull": {
|
|
1541
|
+
const result = await pullProject(call, option("--app") ?? projectApplication());
|
|
1542
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1543
|
+
if (result.status === "blocked") process.exitCode = 1;
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
629
1546
|
case "status": {
|
|
630
1547
|
const prefix = "/apps/" + applicationGuid(option("--app") ?? projectApplication());
|
|
631
1548
|
console.log(JSON.stringify(await call(prefix + "/developer"), null, 2));
|
|
@@ -669,6 +1586,24 @@ async function main() {
|
|
|
669
1586
|
console.log(await call("/apps/requests", { method: "POST", body: JSON.stringify({ workspaceId, name, slug, description, configuration }) }));
|
|
670
1587
|
break;
|
|
671
1588
|
}
|
|
1589
|
+
case "events": {
|
|
1590
|
+
const appId = applicationGuid(option("--app") ?? projectApplication());
|
|
1591
|
+
const prefix = "/apps/" + appId + "/events";
|
|
1592
|
+
if (args[0] === "environments") {
|
|
1593
|
+
console.log(JSON.stringify(await call(prefix + "/environments"), null, 2));
|
|
1594
|
+
break;
|
|
1595
|
+
}
|
|
1596
|
+
const environment = option("--environment");
|
|
1597
|
+
if (!environment || !/^[0-9a-f-]{36}$/i.test(environment)) throw new Error("Use backify events environments, then events inspect|test --environment <UUID> [--name <event> --payload <json-file>]");
|
|
1598
|
+
const path = prefix + "/environments/" + environment;
|
|
1599
|
+
if (args[0] === "inspect") console.log(JSON.stringify(await call(path), null, 2));
|
|
1600
|
+
else if (args[0] === "test") {
|
|
1601
|
+
const name = option("--name"), payload = option("--payload");
|
|
1602
|
+
if (!name || !payload) throw new Error("Specify --name and --payload <json-file>. Never include secrets in event payloads.");
|
|
1603
|
+
console.log(JSON.stringify(await call(path + "/test", { method: "POST", body: JSON.stringify({ name, payload: JSON.parse(readFileSync4(payload, "utf8")), idempotencyKey: option("--idempotency-key") }) }), null, 2));
|
|
1604
|
+
} else throw new Error("Use backify events environments|inspect|test");
|
|
1605
|
+
break;
|
|
1606
|
+
}
|
|
672
1607
|
case "apps":
|
|
673
1608
|
console.table(await call("/apps"));
|
|
674
1609
|
break;
|
|
@@ -676,7 +1611,7 @@ async function main() {
|
|
|
676
1611
|
console.log(await call("/apps/" + applicationGuid(args[0]) + "/deployments/preview", { method: "POST", body: JSON.stringify({ sourceRevision: args[1] ?? "latest" }) }));
|
|
677
1612
|
break;
|
|
678
1613
|
default:
|
|
679
|
-
console.log("backify connect | init | doctor | sync | login | logout | disconnect | status | report [--check] | prompt record --stdin --id <UUID> | ship [--preview-only] | request | apps | deploy");
|
|
1614
|
+
console.log("backify connect | init | doctor | sync | login | logout | disconnect | status | pull | report [--check] | prompt record --stdin --id <UUID> | ship [--preview-only] | request | events environments|inspect|test | apps | deploy");
|
|
680
1615
|
}
|
|
681
1616
|
}
|
|
682
1617
|
main().catch((error) => {
|