@hcrosse/opencode-pr-tracker 0.0.0
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/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/server.js +1966 -0
- package/dist/server.js.map +24 -0
- package/dist/tui.js +2868 -0
- package/dist/tui.js.map +27 -0
- package/package.json +73 -0
package/dist/tui.js
ADDED
|
@@ -0,0 +1,2868 @@
|
|
|
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
|
+
var __require = import.meta.require;
|
|
34
|
+
|
|
35
|
+
// node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js
|
|
36
|
+
var require_polyfills = __commonJS((exports, module) => {
|
|
37
|
+
var constants = __require("constants");
|
|
38
|
+
var origCwd = process.cwd;
|
|
39
|
+
var cwd = null;
|
|
40
|
+
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
41
|
+
process.cwd = function() {
|
|
42
|
+
if (!cwd)
|
|
43
|
+
cwd = origCwd.call(process);
|
|
44
|
+
return cwd;
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
process.cwd();
|
|
48
|
+
} catch (er) {}
|
|
49
|
+
if (typeof process.chdir === "function") {
|
|
50
|
+
chdir = process.chdir;
|
|
51
|
+
process.chdir = function(d) {
|
|
52
|
+
cwd = null;
|
|
53
|
+
chdir.call(process, d);
|
|
54
|
+
};
|
|
55
|
+
if (Object.setPrototypeOf)
|
|
56
|
+
Object.setPrototypeOf(process.chdir, chdir);
|
|
57
|
+
}
|
|
58
|
+
var chdir;
|
|
59
|
+
module.exports = patch;
|
|
60
|
+
function patch(fs) {
|
|
61
|
+
if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
62
|
+
patchLchmod(fs);
|
|
63
|
+
}
|
|
64
|
+
if (!fs.lutimes) {
|
|
65
|
+
patchLutimes(fs);
|
|
66
|
+
}
|
|
67
|
+
fs.chown = chownFix(fs.chown);
|
|
68
|
+
fs.fchown = chownFix(fs.fchown);
|
|
69
|
+
fs.lchown = chownFix(fs.lchown);
|
|
70
|
+
fs.chmod = chmodFix(fs.chmod);
|
|
71
|
+
fs.fchmod = chmodFix(fs.fchmod);
|
|
72
|
+
fs.lchmod = chmodFix(fs.lchmod);
|
|
73
|
+
fs.chownSync = chownFixSync(fs.chownSync);
|
|
74
|
+
fs.fchownSync = chownFixSync(fs.fchownSync);
|
|
75
|
+
fs.lchownSync = chownFixSync(fs.lchownSync);
|
|
76
|
+
fs.chmodSync = chmodFixSync(fs.chmodSync);
|
|
77
|
+
fs.fchmodSync = chmodFixSync(fs.fchmodSync);
|
|
78
|
+
fs.lchmodSync = chmodFixSync(fs.lchmodSync);
|
|
79
|
+
fs.stat = statFix(fs.stat);
|
|
80
|
+
fs.fstat = statFix(fs.fstat);
|
|
81
|
+
fs.lstat = statFix(fs.lstat);
|
|
82
|
+
fs.statSync = statFixSync(fs.statSync);
|
|
83
|
+
fs.fstatSync = statFixSync(fs.fstatSync);
|
|
84
|
+
fs.lstatSync = statFixSync(fs.lstatSync);
|
|
85
|
+
if (fs.chmod && !fs.lchmod) {
|
|
86
|
+
fs.lchmod = function(path, mode, cb) {
|
|
87
|
+
if (cb)
|
|
88
|
+
process.nextTick(cb);
|
|
89
|
+
};
|
|
90
|
+
fs.lchmodSync = function() {};
|
|
91
|
+
}
|
|
92
|
+
if (fs.chown && !fs.lchown) {
|
|
93
|
+
fs.lchown = function(path, uid, gid, cb) {
|
|
94
|
+
if (cb)
|
|
95
|
+
process.nextTick(cb);
|
|
96
|
+
};
|
|
97
|
+
fs.lchownSync = function() {};
|
|
98
|
+
}
|
|
99
|
+
if (platform === "win32") {
|
|
100
|
+
fs.rename = typeof fs.rename !== "function" ? fs.rename : function(fs$rename) {
|
|
101
|
+
function rename(from, to, cb) {
|
|
102
|
+
var start = Date.now();
|
|
103
|
+
var backoff = 0;
|
|
104
|
+
fs$rename(from, to, function CB(er) {
|
|
105
|
+
if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 60000) {
|
|
106
|
+
setTimeout(function() {
|
|
107
|
+
fs.stat(to, function(stater, st) {
|
|
108
|
+
if (stater && stater.code === "ENOENT")
|
|
109
|
+
fs$rename(from, to, CB);
|
|
110
|
+
else
|
|
111
|
+
cb(er);
|
|
112
|
+
});
|
|
113
|
+
}, backoff);
|
|
114
|
+
if (backoff < 100)
|
|
115
|
+
backoff += 10;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (cb)
|
|
119
|
+
cb(er);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (Object.setPrototypeOf)
|
|
123
|
+
Object.setPrototypeOf(rename, fs$rename);
|
|
124
|
+
return rename;
|
|
125
|
+
}(fs.rename);
|
|
126
|
+
}
|
|
127
|
+
fs.read = typeof fs.read !== "function" ? fs.read : function(fs$read) {
|
|
128
|
+
function read(fd, buffer, offset, length, position, callback_) {
|
|
129
|
+
var callback;
|
|
130
|
+
if (callback_ && typeof callback_ === "function") {
|
|
131
|
+
var eagCounter = 0;
|
|
132
|
+
callback = function(er, _, __) {
|
|
133
|
+
if (er && er.code === "EAGAIN" && eagCounter < 10) {
|
|
134
|
+
eagCounter++;
|
|
135
|
+
return fs$read.call(fs, fd, buffer, offset, length, position, callback);
|
|
136
|
+
}
|
|
137
|
+
callback_.apply(this, arguments);
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return fs$read.call(fs, fd, buffer, offset, length, position, callback);
|
|
141
|
+
}
|
|
142
|
+
if (Object.setPrototypeOf)
|
|
143
|
+
Object.setPrototypeOf(read, fs$read);
|
|
144
|
+
return read;
|
|
145
|
+
}(fs.read);
|
|
146
|
+
fs.readSync = typeof fs.readSync !== "function" ? fs.readSync : function(fs$readSync) {
|
|
147
|
+
return function(fd, buffer, offset, length, position) {
|
|
148
|
+
var eagCounter = 0;
|
|
149
|
+
while (true) {
|
|
150
|
+
try {
|
|
151
|
+
return fs$readSync.call(fs, fd, buffer, offset, length, position);
|
|
152
|
+
} catch (er) {
|
|
153
|
+
if (er.code === "EAGAIN" && eagCounter < 10) {
|
|
154
|
+
eagCounter++;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
throw er;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}(fs.readSync);
|
|
162
|
+
function patchLchmod(fs2) {
|
|
163
|
+
fs2.lchmod = function(path, mode, callback) {
|
|
164
|
+
fs2.open(path, constants.O_WRONLY | constants.O_SYMLINK, mode, function(err, fd) {
|
|
165
|
+
if (err) {
|
|
166
|
+
if (callback)
|
|
167
|
+
callback(err);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
fs2.fchmod(fd, mode, function(err2) {
|
|
171
|
+
fs2.close(fd, function(err22) {
|
|
172
|
+
if (callback)
|
|
173
|
+
callback(err2 || err22);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
fs2.lchmodSync = function(path, mode) {
|
|
179
|
+
var fd = fs2.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode);
|
|
180
|
+
var threw = true;
|
|
181
|
+
var ret;
|
|
182
|
+
try {
|
|
183
|
+
ret = fs2.fchmodSync(fd, mode);
|
|
184
|
+
threw = false;
|
|
185
|
+
} finally {
|
|
186
|
+
if (threw) {
|
|
187
|
+
try {
|
|
188
|
+
fs2.closeSync(fd);
|
|
189
|
+
} catch (er) {}
|
|
190
|
+
} else {
|
|
191
|
+
fs2.closeSync(fd);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return ret;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function patchLutimes(fs2) {
|
|
198
|
+
if (constants.hasOwnProperty("O_SYMLINK") && fs2.futimes) {
|
|
199
|
+
fs2.lutimes = function(path, at, mt, cb) {
|
|
200
|
+
fs2.open(path, constants.O_SYMLINK, function(er, fd) {
|
|
201
|
+
if (er) {
|
|
202
|
+
if (cb)
|
|
203
|
+
cb(er);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
fs2.futimes(fd, at, mt, function(er2) {
|
|
207
|
+
fs2.close(fd, function(er22) {
|
|
208
|
+
if (cb)
|
|
209
|
+
cb(er2 || er22);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
fs2.lutimesSync = function(path, at, mt) {
|
|
215
|
+
var fd = fs2.openSync(path, constants.O_SYMLINK);
|
|
216
|
+
var ret;
|
|
217
|
+
var threw = true;
|
|
218
|
+
try {
|
|
219
|
+
ret = fs2.futimesSync(fd, at, mt);
|
|
220
|
+
threw = false;
|
|
221
|
+
} finally {
|
|
222
|
+
if (threw) {
|
|
223
|
+
try {
|
|
224
|
+
fs2.closeSync(fd);
|
|
225
|
+
} catch (er) {}
|
|
226
|
+
} else {
|
|
227
|
+
fs2.closeSync(fd);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return ret;
|
|
231
|
+
};
|
|
232
|
+
} else if (fs2.futimes) {
|
|
233
|
+
fs2.lutimes = function(_a, _b, _c, cb) {
|
|
234
|
+
if (cb)
|
|
235
|
+
process.nextTick(cb);
|
|
236
|
+
};
|
|
237
|
+
fs2.lutimesSync = function() {};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function chmodFix(orig) {
|
|
241
|
+
if (!orig)
|
|
242
|
+
return orig;
|
|
243
|
+
return function(target, mode, cb) {
|
|
244
|
+
return orig.call(fs, target, mode, function(er) {
|
|
245
|
+
if (chownErOk(er))
|
|
246
|
+
er = null;
|
|
247
|
+
if (cb)
|
|
248
|
+
cb.apply(this, arguments);
|
|
249
|
+
});
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function chmodFixSync(orig) {
|
|
253
|
+
if (!orig)
|
|
254
|
+
return orig;
|
|
255
|
+
return function(target, mode) {
|
|
256
|
+
try {
|
|
257
|
+
return orig.call(fs, target, mode);
|
|
258
|
+
} catch (er) {
|
|
259
|
+
if (!chownErOk(er))
|
|
260
|
+
throw er;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function chownFix(orig) {
|
|
265
|
+
if (!orig)
|
|
266
|
+
return orig;
|
|
267
|
+
return function(target, uid, gid, cb) {
|
|
268
|
+
return orig.call(fs, target, uid, gid, function(er) {
|
|
269
|
+
if (chownErOk(er))
|
|
270
|
+
er = null;
|
|
271
|
+
if (cb)
|
|
272
|
+
cb.apply(this, arguments);
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function chownFixSync(orig) {
|
|
277
|
+
if (!orig)
|
|
278
|
+
return orig;
|
|
279
|
+
return function(target, uid, gid) {
|
|
280
|
+
try {
|
|
281
|
+
return orig.call(fs, target, uid, gid);
|
|
282
|
+
} catch (er) {
|
|
283
|
+
if (!chownErOk(er))
|
|
284
|
+
throw er;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function statFix(orig) {
|
|
289
|
+
if (!orig)
|
|
290
|
+
return orig;
|
|
291
|
+
return function(target, options, cb) {
|
|
292
|
+
if (typeof options === "function") {
|
|
293
|
+
cb = options;
|
|
294
|
+
options = null;
|
|
295
|
+
}
|
|
296
|
+
function callback(er, stats) {
|
|
297
|
+
if (stats) {
|
|
298
|
+
if (stats.uid < 0)
|
|
299
|
+
stats.uid += 4294967296;
|
|
300
|
+
if (stats.gid < 0)
|
|
301
|
+
stats.gid += 4294967296;
|
|
302
|
+
}
|
|
303
|
+
if (cb)
|
|
304
|
+
cb.apply(this, arguments);
|
|
305
|
+
}
|
|
306
|
+
return options ? orig.call(fs, target, options, callback) : orig.call(fs, target, callback);
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function statFixSync(orig) {
|
|
310
|
+
if (!orig)
|
|
311
|
+
return orig;
|
|
312
|
+
return function(target, options) {
|
|
313
|
+
var stats = options ? orig.call(fs, target, options) : orig.call(fs, target);
|
|
314
|
+
if (stats) {
|
|
315
|
+
if (stats.uid < 0)
|
|
316
|
+
stats.uid += 4294967296;
|
|
317
|
+
if (stats.gid < 0)
|
|
318
|
+
stats.gid += 4294967296;
|
|
319
|
+
}
|
|
320
|
+
return stats;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function chownErOk(er) {
|
|
324
|
+
if (!er)
|
|
325
|
+
return true;
|
|
326
|
+
if (er.code === "ENOSYS")
|
|
327
|
+
return true;
|
|
328
|
+
var nonroot = !process.getuid || process.getuid() !== 0;
|
|
329
|
+
if (nonroot) {
|
|
330
|
+
if (er.code === "EINVAL" || er.code === "EPERM")
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/legacy-streams.js
|
|
339
|
+
var require_legacy_streams = __commonJS((exports, module) => {
|
|
340
|
+
var Stream = __require("stream").Stream;
|
|
341
|
+
module.exports = legacy;
|
|
342
|
+
function legacy(fs) {
|
|
343
|
+
return {
|
|
344
|
+
ReadStream,
|
|
345
|
+
WriteStream
|
|
346
|
+
};
|
|
347
|
+
function ReadStream(path, options) {
|
|
348
|
+
if (!(this instanceof ReadStream))
|
|
349
|
+
return new ReadStream(path, options);
|
|
350
|
+
Stream.call(this);
|
|
351
|
+
var self = this;
|
|
352
|
+
this.path = path;
|
|
353
|
+
this.fd = null;
|
|
354
|
+
this.readable = true;
|
|
355
|
+
this.paused = false;
|
|
356
|
+
this.flags = "r";
|
|
357
|
+
this.mode = 438;
|
|
358
|
+
this.bufferSize = 64 * 1024;
|
|
359
|
+
options = options || {};
|
|
360
|
+
var keys = Object.keys(options);
|
|
361
|
+
for (var index = 0, length = keys.length;index < length; index++) {
|
|
362
|
+
var key = keys[index];
|
|
363
|
+
this[key] = options[key];
|
|
364
|
+
}
|
|
365
|
+
if (this.encoding)
|
|
366
|
+
this.setEncoding(this.encoding);
|
|
367
|
+
if (this.start !== undefined) {
|
|
368
|
+
if (typeof this.start !== "number") {
|
|
369
|
+
throw TypeError("start must be a Number");
|
|
370
|
+
}
|
|
371
|
+
if (this.end === undefined) {
|
|
372
|
+
this.end = Infinity;
|
|
373
|
+
} else if (typeof this.end !== "number") {
|
|
374
|
+
throw TypeError("end must be a Number");
|
|
375
|
+
}
|
|
376
|
+
if (this.start > this.end) {
|
|
377
|
+
throw new Error("start must be <= end");
|
|
378
|
+
}
|
|
379
|
+
this.pos = this.start;
|
|
380
|
+
}
|
|
381
|
+
if (this.fd !== null) {
|
|
382
|
+
process.nextTick(function() {
|
|
383
|
+
self._read();
|
|
384
|
+
});
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
fs.open(this.path, this.flags, this.mode, function(err, fd) {
|
|
388
|
+
if (err) {
|
|
389
|
+
self.emit("error", err);
|
|
390
|
+
self.readable = false;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
self.fd = fd;
|
|
394
|
+
self.emit("open", fd);
|
|
395
|
+
self._read();
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
function WriteStream(path, options) {
|
|
399
|
+
if (!(this instanceof WriteStream))
|
|
400
|
+
return new WriteStream(path, options);
|
|
401
|
+
Stream.call(this);
|
|
402
|
+
this.path = path;
|
|
403
|
+
this.fd = null;
|
|
404
|
+
this.writable = true;
|
|
405
|
+
this.flags = "w";
|
|
406
|
+
this.encoding = "binary";
|
|
407
|
+
this.mode = 438;
|
|
408
|
+
this.bytesWritten = 0;
|
|
409
|
+
options = options || {};
|
|
410
|
+
var keys = Object.keys(options);
|
|
411
|
+
for (var index = 0, length = keys.length;index < length; index++) {
|
|
412
|
+
var key = keys[index];
|
|
413
|
+
this[key] = options[key];
|
|
414
|
+
}
|
|
415
|
+
if (this.start !== undefined) {
|
|
416
|
+
if (typeof this.start !== "number") {
|
|
417
|
+
throw TypeError("start must be a Number");
|
|
418
|
+
}
|
|
419
|
+
if (this.start < 0) {
|
|
420
|
+
throw new Error("start must be >= zero");
|
|
421
|
+
}
|
|
422
|
+
this.pos = this.start;
|
|
423
|
+
}
|
|
424
|
+
this.busy = false;
|
|
425
|
+
this._queue = [];
|
|
426
|
+
if (this.fd === null) {
|
|
427
|
+
this._open = fs.open;
|
|
428
|
+
this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
|
|
429
|
+
this.flush();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/clone.js
|
|
436
|
+
var require_clone = __commonJS((exports, module) => {
|
|
437
|
+
module.exports = clone;
|
|
438
|
+
var getPrototypeOf = Object.getPrototypeOf || function(obj) {
|
|
439
|
+
return obj.__proto__;
|
|
440
|
+
};
|
|
441
|
+
function clone(obj) {
|
|
442
|
+
if (obj === null || typeof obj !== "object")
|
|
443
|
+
return obj;
|
|
444
|
+
if (obj instanceof Object)
|
|
445
|
+
var copy = { __proto__: getPrototypeOf(obj) };
|
|
446
|
+
else
|
|
447
|
+
var copy = Object.create(null);
|
|
448
|
+
Object.getOwnPropertyNames(obj).forEach(function(key) {
|
|
449
|
+
Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key));
|
|
450
|
+
});
|
|
451
|
+
return copy;
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js
|
|
456
|
+
var require_graceful_fs = __commonJS((exports, module) => {
|
|
457
|
+
var fs = __require("fs");
|
|
458
|
+
var polyfills = require_polyfills();
|
|
459
|
+
var legacy = require_legacy_streams();
|
|
460
|
+
var clone = require_clone();
|
|
461
|
+
var util = __require("util");
|
|
462
|
+
var gracefulQueue;
|
|
463
|
+
var previousSymbol;
|
|
464
|
+
if (typeof Symbol === "function" && typeof Symbol.for === "function") {
|
|
465
|
+
gracefulQueue = Symbol.for("graceful-fs.queue");
|
|
466
|
+
previousSymbol = Symbol.for("graceful-fs.previous");
|
|
467
|
+
} else {
|
|
468
|
+
gracefulQueue = "___graceful-fs.queue";
|
|
469
|
+
previousSymbol = "___graceful-fs.previous";
|
|
470
|
+
}
|
|
471
|
+
function noop() {}
|
|
472
|
+
function publishQueue(context, queue2) {
|
|
473
|
+
Object.defineProperty(context, gracefulQueue, {
|
|
474
|
+
get: function() {
|
|
475
|
+
return queue2;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
var debug = noop;
|
|
480
|
+
if (util.debuglog)
|
|
481
|
+
debug = util.debuglog("gfs4");
|
|
482
|
+
else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ""))
|
|
483
|
+
debug = function() {
|
|
484
|
+
var m = util.format.apply(util, arguments);
|
|
485
|
+
m = "GFS4: " + m.split(/\n/).join(`
|
|
486
|
+
GFS4: `);
|
|
487
|
+
console.error(m);
|
|
488
|
+
};
|
|
489
|
+
if (!fs[gracefulQueue]) {
|
|
490
|
+
queue = global[gracefulQueue] || [];
|
|
491
|
+
publishQueue(fs, queue);
|
|
492
|
+
fs.close = function(fs$close) {
|
|
493
|
+
function close(fd, cb) {
|
|
494
|
+
return fs$close.call(fs, fd, function(err) {
|
|
495
|
+
if (!err) {
|
|
496
|
+
resetQueue();
|
|
497
|
+
}
|
|
498
|
+
if (typeof cb === "function")
|
|
499
|
+
cb.apply(this, arguments);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
Object.defineProperty(close, previousSymbol, {
|
|
503
|
+
value: fs$close
|
|
504
|
+
});
|
|
505
|
+
return close;
|
|
506
|
+
}(fs.close);
|
|
507
|
+
fs.closeSync = function(fs$closeSync) {
|
|
508
|
+
function closeSync(fd) {
|
|
509
|
+
fs$closeSync.apply(fs, arguments);
|
|
510
|
+
resetQueue();
|
|
511
|
+
}
|
|
512
|
+
Object.defineProperty(closeSync, previousSymbol, {
|
|
513
|
+
value: fs$closeSync
|
|
514
|
+
});
|
|
515
|
+
return closeSync;
|
|
516
|
+
}(fs.closeSync);
|
|
517
|
+
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
518
|
+
process.on("exit", function() {
|
|
519
|
+
debug(fs[gracefulQueue]);
|
|
520
|
+
__require("assert").equal(fs[gracefulQueue].length, 0);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
var queue;
|
|
525
|
+
if (!global[gracefulQueue]) {
|
|
526
|
+
publishQueue(global, fs[gracefulQueue]);
|
|
527
|
+
}
|
|
528
|
+
module.exports = patch(clone(fs));
|
|
529
|
+
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
|
|
530
|
+
module.exports = patch(fs);
|
|
531
|
+
fs.__patched = true;
|
|
532
|
+
}
|
|
533
|
+
function patch(fs2) {
|
|
534
|
+
polyfills(fs2);
|
|
535
|
+
fs2.gracefulify = patch;
|
|
536
|
+
fs2.createReadStream = createReadStream;
|
|
537
|
+
fs2.createWriteStream = createWriteStream;
|
|
538
|
+
var fs$readFile = fs2.readFile;
|
|
539
|
+
fs2.readFile = readFile;
|
|
540
|
+
function readFile(path, options, cb) {
|
|
541
|
+
if (typeof options === "function")
|
|
542
|
+
cb = options, options = null;
|
|
543
|
+
return go$readFile(path, options, cb);
|
|
544
|
+
function go$readFile(path2, options2, cb2, startTime) {
|
|
545
|
+
return fs$readFile(path2, options2, function(err) {
|
|
546
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
547
|
+
enqueue([go$readFile, [path2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
548
|
+
else {
|
|
549
|
+
if (typeof cb2 === "function")
|
|
550
|
+
cb2.apply(this, arguments);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
var fs$writeFile = fs2.writeFile;
|
|
556
|
+
fs2.writeFile = writeFile;
|
|
557
|
+
function writeFile(path, data, options, cb) {
|
|
558
|
+
if (typeof options === "function")
|
|
559
|
+
cb = options, options = null;
|
|
560
|
+
return go$writeFile(path, data, options, cb);
|
|
561
|
+
function go$writeFile(path2, data2, options2, cb2, startTime) {
|
|
562
|
+
return fs$writeFile(path2, data2, options2, function(err) {
|
|
563
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
564
|
+
enqueue([go$writeFile, [path2, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
565
|
+
else {
|
|
566
|
+
if (typeof cb2 === "function")
|
|
567
|
+
cb2.apply(this, arguments);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
var fs$appendFile = fs2.appendFile;
|
|
573
|
+
if (fs$appendFile)
|
|
574
|
+
fs2.appendFile = appendFile;
|
|
575
|
+
function appendFile(path, data, options, cb) {
|
|
576
|
+
if (typeof options === "function")
|
|
577
|
+
cb = options, options = null;
|
|
578
|
+
return go$appendFile(path, data, options, cb);
|
|
579
|
+
function go$appendFile(path2, data2, options2, cb2, startTime) {
|
|
580
|
+
return fs$appendFile(path2, data2, options2, function(err) {
|
|
581
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
582
|
+
enqueue([go$appendFile, [path2, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
583
|
+
else {
|
|
584
|
+
if (typeof cb2 === "function")
|
|
585
|
+
cb2.apply(this, arguments);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
var fs$copyFile = fs2.copyFile;
|
|
591
|
+
if (fs$copyFile)
|
|
592
|
+
fs2.copyFile = copyFile;
|
|
593
|
+
function copyFile(src, dest, flags, cb) {
|
|
594
|
+
if (typeof flags === "function") {
|
|
595
|
+
cb = flags;
|
|
596
|
+
flags = 0;
|
|
597
|
+
}
|
|
598
|
+
return go$copyFile(src, dest, flags, cb);
|
|
599
|
+
function go$copyFile(src2, dest2, flags2, cb2, startTime) {
|
|
600
|
+
return fs$copyFile(src2, dest2, flags2, function(err) {
|
|
601
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
602
|
+
enqueue([go$copyFile, [src2, dest2, flags2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
603
|
+
else {
|
|
604
|
+
if (typeof cb2 === "function")
|
|
605
|
+
cb2.apply(this, arguments);
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
var fs$readdir = fs2.readdir;
|
|
611
|
+
fs2.readdir = readdir;
|
|
612
|
+
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
613
|
+
function readdir(path, options, cb) {
|
|
614
|
+
if (typeof options === "function")
|
|
615
|
+
cb = options, options = null;
|
|
616
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path2, options2, cb2, startTime) {
|
|
617
|
+
return fs$readdir(path2, fs$readdirCallback(path2, options2, cb2, startTime));
|
|
618
|
+
} : function go$readdir2(path2, options2, cb2, startTime) {
|
|
619
|
+
return fs$readdir(path2, options2, fs$readdirCallback(path2, options2, cb2, startTime));
|
|
620
|
+
};
|
|
621
|
+
return go$readdir(path, options, cb);
|
|
622
|
+
function fs$readdirCallback(path2, options2, cb2, startTime) {
|
|
623
|
+
return function(err, files) {
|
|
624
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
625
|
+
enqueue([
|
|
626
|
+
go$readdir,
|
|
627
|
+
[path2, options2, cb2],
|
|
628
|
+
err,
|
|
629
|
+
startTime || Date.now(),
|
|
630
|
+
Date.now()
|
|
631
|
+
]);
|
|
632
|
+
else {
|
|
633
|
+
if (files && files.sort)
|
|
634
|
+
files.sort();
|
|
635
|
+
if (typeof cb2 === "function")
|
|
636
|
+
cb2.call(this, err, files);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (process.version.substr(0, 4) === "v0.8") {
|
|
642
|
+
var legStreams = legacy(fs2);
|
|
643
|
+
ReadStream = legStreams.ReadStream;
|
|
644
|
+
WriteStream = legStreams.WriteStream;
|
|
645
|
+
}
|
|
646
|
+
var fs$ReadStream = fs2.ReadStream;
|
|
647
|
+
if (fs$ReadStream) {
|
|
648
|
+
ReadStream.prototype = Object.create(fs$ReadStream.prototype);
|
|
649
|
+
ReadStream.prototype.open = ReadStream$open;
|
|
650
|
+
}
|
|
651
|
+
var fs$WriteStream = fs2.WriteStream;
|
|
652
|
+
if (fs$WriteStream) {
|
|
653
|
+
WriteStream.prototype = Object.create(fs$WriteStream.prototype);
|
|
654
|
+
WriteStream.prototype.open = WriteStream$open;
|
|
655
|
+
}
|
|
656
|
+
Object.defineProperty(fs2, "ReadStream", {
|
|
657
|
+
get: function() {
|
|
658
|
+
return ReadStream;
|
|
659
|
+
},
|
|
660
|
+
set: function(val) {
|
|
661
|
+
ReadStream = val;
|
|
662
|
+
},
|
|
663
|
+
enumerable: true,
|
|
664
|
+
configurable: true
|
|
665
|
+
});
|
|
666
|
+
Object.defineProperty(fs2, "WriteStream", {
|
|
667
|
+
get: function() {
|
|
668
|
+
return WriteStream;
|
|
669
|
+
},
|
|
670
|
+
set: function(val) {
|
|
671
|
+
WriteStream = val;
|
|
672
|
+
},
|
|
673
|
+
enumerable: true,
|
|
674
|
+
configurable: true
|
|
675
|
+
});
|
|
676
|
+
var FileReadStream = ReadStream;
|
|
677
|
+
Object.defineProperty(fs2, "FileReadStream", {
|
|
678
|
+
get: function() {
|
|
679
|
+
return FileReadStream;
|
|
680
|
+
},
|
|
681
|
+
set: function(val) {
|
|
682
|
+
FileReadStream = val;
|
|
683
|
+
},
|
|
684
|
+
enumerable: true,
|
|
685
|
+
configurable: true
|
|
686
|
+
});
|
|
687
|
+
var FileWriteStream = WriteStream;
|
|
688
|
+
Object.defineProperty(fs2, "FileWriteStream", {
|
|
689
|
+
get: function() {
|
|
690
|
+
return FileWriteStream;
|
|
691
|
+
},
|
|
692
|
+
set: function(val) {
|
|
693
|
+
FileWriteStream = val;
|
|
694
|
+
},
|
|
695
|
+
enumerable: true,
|
|
696
|
+
configurable: true
|
|
697
|
+
});
|
|
698
|
+
function ReadStream(path, options) {
|
|
699
|
+
if (this instanceof ReadStream)
|
|
700
|
+
return fs$ReadStream.apply(this, arguments), this;
|
|
701
|
+
else
|
|
702
|
+
return ReadStream.apply(Object.create(ReadStream.prototype), arguments);
|
|
703
|
+
}
|
|
704
|
+
function ReadStream$open() {
|
|
705
|
+
var that = this;
|
|
706
|
+
open(that.path, that.flags, that.mode, function(err, fd) {
|
|
707
|
+
if (err) {
|
|
708
|
+
if (that.autoClose)
|
|
709
|
+
that.destroy();
|
|
710
|
+
that.emit("error", err);
|
|
711
|
+
} else {
|
|
712
|
+
that.fd = fd;
|
|
713
|
+
that.emit("open", fd);
|
|
714
|
+
that.read();
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
function WriteStream(path, options) {
|
|
719
|
+
if (this instanceof WriteStream)
|
|
720
|
+
return fs$WriteStream.apply(this, arguments), this;
|
|
721
|
+
else
|
|
722
|
+
return WriteStream.apply(Object.create(WriteStream.prototype), arguments);
|
|
723
|
+
}
|
|
724
|
+
function WriteStream$open() {
|
|
725
|
+
var that = this;
|
|
726
|
+
open(that.path, that.flags, that.mode, function(err, fd) {
|
|
727
|
+
if (err) {
|
|
728
|
+
that.destroy();
|
|
729
|
+
that.emit("error", err);
|
|
730
|
+
} else {
|
|
731
|
+
that.fd = fd;
|
|
732
|
+
that.emit("open", fd);
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
function createReadStream(path, options) {
|
|
737
|
+
return new fs2.ReadStream(path, options);
|
|
738
|
+
}
|
|
739
|
+
function createWriteStream(path, options) {
|
|
740
|
+
return new fs2.WriteStream(path, options);
|
|
741
|
+
}
|
|
742
|
+
var fs$open = fs2.open;
|
|
743
|
+
fs2.open = open;
|
|
744
|
+
function open(path, flags, mode, cb) {
|
|
745
|
+
if (typeof mode === "function")
|
|
746
|
+
cb = mode, mode = null;
|
|
747
|
+
return go$open(path, flags, mode, cb);
|
|
748
|
+
function go$open(path2, flags2, mode2, cb2, startTime) {
|
|
749
|
+
return fs$open(path2, flags2, mode2, function(err, fd) {
|
|
750
|
+
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
751
|
+
enqueue([go$open, [path2, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
752
|
+
else {
|
|
753
|
+
if (typeof cb2 === "function")
|
|
754
|
+
cb2.apply(this, arguments);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return fs2;
|
|
760
|
+
}
|
|
761
|
+
function enqueue(elem) {
|
|
762
|
+
debug("ENQUEUE", elem[0].name, elem[1]);
|
|
763
|
+
fs[gracefulQueue].push(elem);
|
|
764
|
+
retry();
|
|
765
|
+
}
|
|
766
|
+
var retryTimer;
|
|
767
|
+
function resetQueue() {
|
|
768
|
+
var now = Date.now();
|
|
769
|
+
for (var i = 0;i < fs[gracefulQueue].length; ++i) {
|
|
770
|
+
if (fs[gracefulQueue][i].length > 2) {
|
|
771
|
+
fs[gracefulQueue][i][3] = now;
|
|
772
|
+
fs[gracefulQueue][i][4] = now;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
retry();
|
|
776
|
+
}
|
|
777
|
+
function retry() {
|
|
778
|
+
clearTimeout(retryTimer);
|
|
779
|
+
retryTimer = undefined;
|
|
780
|
+
if (fs[gracefulQueue].length === 0)
|
|
781
|
+
return;
|
|
782
|
+
var elem = fs[gracefulQueue].shift();
|
|
783
|
+
var fn = elem[0];
|
|
784
|
+
var args = elem[1];
|
|
785
|
+
var err = elem[2];
|
|
786
|
+
var startTime = elem[3];
|
|
787
|
+
var lastTime = elem[4];
|
|
788
|
+
if (startTime === undefined) {
|
|
789
|
+
debug("RETRY", fn.name, args);
|
|
790
|
+
fn.apply(null, args);
|
|
791
|
+
} else if (Date.now() - startTime >= 60000) {
|
|
792
|
+
debug("TIMEOUT", fn.name, args);
|
|
793
|
+
var cb = args.pop();
|
|
794
|
+
if (typeof cb === "function")
|
|
795
|
+
cb.call(null, err);
|
|
796
|
+
} else {
|
|
797
|
+
var sinceAttempt = Date.now() - lastTime;
|
|
798
|
+
var sinceStart = Math.max(lastTime - startTime, 1);
|
|
799
|
+
var desiredDelay = Math.min(sinceStart * 1.2, 100);
|
|
800
|
+
if (sinceAttempt >= desiredDelay) {
|
|
801
|
+
debug("RETRY", fn.name, args);
|
|
802
|
+
fn.apply(null, args.concat([startTime]));
|
|
803
|
+
} else {
|
|
804
|
+
fs[gracefulQueue].push(elem);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
if (retryTimer === undefined) {
|
|
808
|
+
retryTimer = setTimeout(retry, 0);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
// node_modules/.bun/retry@0.12.0/node_modules/retry/lib/retry_operation.js
|
|
814
|
+
var require_retry_operation = __commonJS((exports, module) => {
|
|
815
|
+
function RetryOperation(timeouts, options) {
|
|
816
|
+
if (typeof options === "boolean") {
|
|
817
|
+
options = { forever: options };
|
|
818
|
+
}
|
|
819
|
+
this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
|
|
820
|
+
this._timeouts = timeouts;
|
|
821
|
+
this._options = options || {};
|
|
822
|
+
this._maxRetryTime = options && options.maxRetryTime || Infinity;
|
|
823
|
+
this._fn = null;
|
|
824
|
+
this._errors = [];
|
|
825
|
+
this._attempts = 1;
|
|
826
|
+
this._operationTimeout = null;
|
|
827
|
+
this._operationTimeoutCb = null;
|
|
828
|
+
this._timeout = null;
|
|
829
|
+
this._operationStart = null;
|
|
830
|
+
if (this._options.forever) {
|
|
831
|
+
this._cachedTimeouts = this._timeouts.slice(0);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
module.exports = RetryOperation;
|
|
835
|
+
RetryOperation.prototype.reset = function() {
|
|
836
|
+
this._attempts = 1;
|
|
837
|
+
this._timeouts = this._originalTimeouts;
|
|
838
|
+
};
|
|
839
|
+
RetryOperation.prototype.stop = function() {
|
|
840
|
+
if (this._timeout) {
|
|
841
|
+
clearTimeout(this._timeout);
|
|
842
|
+
}
|
|
843
|
+
this._timeouts = [];
|
|
844
|
+
this._cachedTimeouts = null;
|
|
845
|
+
};
|
|
846
|
+
RetryOperation.prototype.retry = function(err) {
|
|
847
|
+
if (this._timeout) {
|
|
848
|
+
clearTimeout(this._timeout);
|
|
849
|
+
}
|
|
850
|
+
if (!err) {
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
var currentTime = new Date().getTime();
|
|
854
|
+
if (err && currentTime - this._operationStart >= this._maxRetryTime) {
|
|
855
|
+
this._errors.unshift(new Error("RetryOperation timeout occurred"));
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
this._errors.push(err);
|
|
859
|
+
var timeout = this._timeouts.shift();
|
|
860
|
+
if (timeout === undefined) {
|
|
861
|
+
if (this._cachedTimeouts) {
|
|
862
|
+
this._errors.splice(this._errors.length - 1, this._errors.length);
|
|
863
|
+
this._timeouts = this._cachedTimeouts.slice(0);
|
|
864
|
+
timeout = this._timeouts.shift();
|
|
865
|
+
} else {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
var self = this;
|
|
870
|
+
var timer = setTimeout(function() {
|
|
871
|
+
self._attempts++;
|
|
872
|
+
if (self._operationTimeoutCb) {
|
|
873
|
+
self._timeout = setTimeout(function() {
|
|
874
|
+
self._operationTimeoutCb(self._attempts);
|
|
875
|
+
}, self._operationTimeout);
|
|
876
|
+
if (self._options.unref) {
|
|
877
|
+
self._timeout.unref();
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
self._fn(self._attempts);
|
|
881
|
+
}, timeout);
|
|
882
|
+
if (this._options.unref) {
|
|
883
|
+
timer.unref();
|
|
884
|
+
}
|
|
885
|
+
return true;
|
|
886
|
+
};
|
|
887
|
+
RetryOperation.prototype.attempt = function(fn, timeoutOps) {
|
|
888
|
+
this._fn = fn;
|
|
889
|
+
if (timeoutOps) {
|
|
890
|
+
if (timeoutOps.timeout) {
|
|
891
|
+
this._operationTimeout = timeoutOps.timeout;
|
|
892
|
+
}
|
|
893
|
+
if (timeoutOps.cb) {
|
|
894
|
+
this._operationTimeoutCb = timeoutOps.cb;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
var self = this;
|
|
898
|
+
if (this._operationTimeoutCb) {
|
|
899
|
+
this._timeout = setTimeout(function() {
|
|
900
|
+
self._operationTimeoutCb();
|
|
901
|
+
}, self._operationTimeout);
|
|
902
|
+
}
|
|
903
|
+
this._operationStart = new Date().getTime();
|
|
904
|
+
this._fn(this._attempts);
|
|
905
|
+
};
|
|
906
|
+
RetryOperation.prototype.try = function(fn) {
|
|
907
|
+
console.log("Using RetryOperation.try() is deprecated");
|
|
908
|
+
this.attempt(fn);
|
|
909
|
+
};
|
|
910
|
+
RetryOperation.prototype.start = function(fn) {
|
|
911
|
+
console.log("Using RetryOperation.start() is deprecated");
|
|
912
|
+
this.attempt(fn);
|
|
913
|
+
};
|
|
914
|
+
RetryOperation.prototype.start = RetryOperation.prototype.try;
|
|
915
|
+
RetryOperation.prototype.errors = function() {
|
|
916
|
+
return this._errors;
|
|
917
|
+
};
|
|
918
|
+
RetryOperation.prototype.attempts = function() {
|
|
919
|
+
return this._attempts;
|
|
920
|
+
};
|
|
921
|
+
RetryOperation.prototype.mainError = function() {
|
|
922
|
+
if (this._errors.length === 0) {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
var counts = {};
|
|
926
|
+
var mainError = null;
|
|
927
|
+
var mainErrorCount = 0;
|
|
928
|
+
for (var i = 0;i < this._errors.length; i++) {
|
|
929
|
+
var error = this._errors[i];
|
|
930
|
+
var message = error.message;
|
|
931
|
+
var count = (counts[message] || 0) + 1;
|
|
932
|
+
counts[message] = count;
|
|
933
|
+
if (count >= mainErrorCount) {
|
|
934
|
+
mainError = error;
|
|
935
|
+
mainErrorCount = count;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return mainError;
|
|
939
|
+
};
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
// node_modules/.bun/retry@0.12.0/node_modules/retry/lib/retry.js
|
|
943
|
+
var require_retry = __commonJS((exports) => {
|
|
944
|
+
var RetryOperation = require_retry_operation();
|
|
945
|
+
exports.operation = function(options) {
|
|
946
|
+
var timeouts = exports.timeouts(options);
|
|
947
|
+
return new RetryOperation(timeouts, {
|
|
948
|
+
forever: options && options.forever,
|
|
949
|
+
unref: options && options.unref,
|
|
950
|
+
maxRetryTime: options && options.maxRetryTime
|
|
951
|
+
});
|
|
952
|
+
};
|
|
953
|
+
exports.timeouts = function(options) {
|
|
954
|
+
if (options instanceof Array) {
|
|
955
|
+
return [].concat(options);
|
|
956
|
+
}
|
|
957
|
+
var opts = {
|
|
958
|
+
retries: 10,
|
|
959
|
+
factor: 2,
|
|
960
|
+
minTimeout: 1 * 1000,
|
|
961
|
+
maxTimeout: Infinity,
|
|
962
|
+
randomize: false
|
|
963
|
+
};
|
|
964
|
+
for (var key in options) {
|
|
965
|
+
opts[key] = options[key];
|
|
966
|
+
}
|
|
967
|
+
if (opts.minTimeout > opts.maxTimeout) {
|
|
968
|
+
throw new Error("minTimeout is greater than maxTimeout");
|
|
969
|
+
}
|
|
970
|
+
var timeouts = [];
|
|
971
|
+
for (var i = 0;i < opts.retries; i++) {
|
|
972
|
+
timeouts.push(this.createTimeout(i, opts));
|
|
973
|
+
}
|
|
974
|
+
if (options && options.forever && !timeouts.length) {
|
|
975
|
+
timeouts.push(this.createTimeout(i, opts));
|
|
976
|
+
}
|
|
977
|
+
timeouts.sort(function(a, b) {
|
|
978
|
+
return a - b;
|
|
979
|
+
});
|
|
980
|
+
return timeouts;
|
|
981
|
+
};
|
|
982
|
+
exports.createTimeout = function(attempt, opts) {
|
|
983
|
+
var random = opts.randomize ? Math.random() + 1 : 1;
|
|
984
|
+
var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
|
|
985
|
+
timeout = Math.min(timeout, opts.maxTimeout);
|
|
986
|
+
return timeout;
|
|
987
|
+
};
|
|
988
|
+
exports.wrap = function(obj, options, methods) {
|
|
989
|
+
if (options instanceof Array) {
|
|
990
|
+
methods = options;
|
|
991
|
+
options = null;
|
|
992
|
+
}
|
|
993
|
+
if (!methods) {
|
|
994
|
+
methods = [];
|
|
995
|
+
for (var key in obj) {
|
|
996
|
+
if (typeof obj[key] === "function") {
|
|
997
|
+
methods.push(key);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
for (var i = 0;i < methods.length; i++) {
|
|
1002
|
+
var method = methods[i];
|
|
1003
|
+
var original = obj[method];
|
|
1004
|
+
obj[method] = function retryWrapper(original2) {
|
|
1005
|
+
var op = exports.operation(options);
|
|
1006
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
1007
|
+
var callback = args.pop();
|
|
1008
|
+
args.push(function(err) {
|
|
1009
|
+
if (op.retry(err)) {
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
if (err) {
|
|
1013
|
+
arguments[0] = op.mainError();
|
|
1014
|
+
}
|
|
1015
|
+
callback.apply(this, arguments);
|
|
1016
|
+
});
|
|
1017
|
+
op.attempt(function() {
|
|
1018
|
+
original2.apply(obj, args);
|
|
1019
|
+
});
|
|
1020
|
+
}.bind(obj, original);
|
|
1021
|
+
obj[method].options = options;
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
// node_modules/.bun/signal-exit@3.0.7/node_modules/signal-exit/signals.js
|
|
1027
|
+
var require_signals = __commonJS((exports, module) => {
|
|
1028
|
+
module.exports = [
|
|
1029
|
+
"SIGABRT",
|
|
1030
|
+
"SIGALRM",
|
|
1031
|
+
"SIGHUP",
|
|
1032
|
+
"SIGINT",
|
|
1033
|
+
"SIGTERM"
|
|
1034
|
+
];
|
|
1035
|
+
if (process.platform !== "win32") {
|
|
1036
|
+
module.exports.push("SIGVTALRM", "SIGXCPU", "SIGXFSZ", "SIGUSR2", "SIGTRAP", "SIGSYS", "SIGQUIT", "SIGIOT");
|
|
1037
|
+
}
|
|
1038
|
+
if (process.platform === "linux") {
|
|
1039
|
+
module.exports.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT", "SIGUNUSED");
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
// node_modules/.bun/signal-exit@3.0.7/node_modules/signal-exit/index.js
|
|
1044
|
+
var require_signal_exit = __commonJS((exports, module) => {
|
|
1045
|
+
var process2 = global.process;
|
|
1046
|
+
var processOk = function(process3) {
|
|
1047
|
+
return process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function";
|
|
1048
|
+
};
|
|
1049
|
+
if (!processOk(process2)) {
|
|
1050
|
+
module.exports = function() {
|
|
1051
|
+
return function() {};
|
|
1052
|
+
};
|
|
1053
|
+
} else {
|
|
1054
|
+
assert = __require("assert");
|
|
1055
|
+
signals = require_signals();
|
|
1056
|
+
isWin = /^win/i.test(process2.platform);
|
|
1057
|
+
EE = __require("events");
|
|
1058
|
+
if (typeof EE !== "function") {
|
|
1059
|
+
EE = EE.EventEmitter;
|
|
1060
|
+
}
|
|
1061
|
+
if (process2.__signal_exit_emitter__) {
|
|
1062
|
+
emitter = process2.__signal_exit_emitter__;
|
|
1063
|
+
} else {
|
|
1064
|
+
emitter = process2.__signal_exit_emitter__ = new EE;
|
|
1065
|
+
emitter.count = 0;
|
|
1066
|
+
emitter.emitted = {};
|
|
1067
|
+
}
|
|
1068
|
+
if (!emitter.infinite) {
|
|
1069
|
+
emitter.setMaxListeners(Infinity);
|
|
1070
|
+
emitter.infinite = true;
|
|
1071
|
+
}
|
|
1072
|
+
module.exports = function(cb, opts) {
|
|
1073
|
+
if (!processOk(global.process)) {
|
|
1074
|
+
return function() {};
|
|
1075
|
+
}
|
|
1076
|
+
assert.equal(typeof cb, "function", "a callback must be provided for exit handler");
|
|
1077
|
+
if (loaded === false) {
|
|
1078
|
+
load();
|
|
1079
|
+
}
|
|
1080
|
+
var ev = "exit";
|
|
1081
|
+
if (opts && opts.alwaysLast) {
|
|
1082
|
+
ev = "afterexit";
|
|
1083
|
+
}
|
|
1084
|
+
var remove = function() {
|
|
1085
|
+
emitter.removeListener(ev, cb);
|
|
1086
|
+
if (emitter.listeners("exit").length === 0 && emitter.listeners("afterexit").length === 0) {
|
|
1087
|
+
unload();
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
emitter.on(ev, cb);
|
|
1091
|
+
return remove;
|
|
1092
|
+
};
|
|
1093
|
+
unload = function unload2() {
|
|
1094
|
+
if (!loaded || !processOk(global.process)) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
loaded = false;
|
|
1098
|
+
signals.forEach(function(sig) {
|
|
1099
|
+
try {
|
|
1100
|
+
process2.removeListener(sig, sigListeners[sig]);
|
|
1101
|
+
} catch (er) {}
|
|
1102
|
+
});
|
|
1103
|
+
process2.emit = originalProcessEmit;
|
|
1104
|
+
process2.reallyExit = originalProcessReallyExit;
|
|
1105
|
+
emitter.count -= 1;
|
|
1106
|
+
};
|
|
1107
|
+
module.exports.unload = unload;
|
|
1108
|
+
emit = function emit2(event, code, signal) {
|
|
1109
|
+
if (emitter.emitted[event]) {
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
emitter.emitted[event] = true;
|
|
1113
|
+
emitter.emit(event, code, signal);
|
|
1114
|
+
};
|
|
1115
|
+
sigListeners = {};
|
|
1116
|
+
signals.forEach(function(sig) {
|
|
1117
|
+
sigListeners[sig] = function listener() {
|
|
1118
|
+
if (!processOk(global.process)) {
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
var listeners = process2.listeners(sig);
|
|
1122
|
+
if (listeners.length === emitter.count) {
|
|
1123
|
+
unload();
|
|
1124
|
+
emit("exit", null, sig);
|
|
1125
|
+
emit("afterexit", null, sig);
|
|
1126
|
+
if (isWin && sig === "SIGHUP") {
|
|
1127
|
+
sig = "SIGINT";
|
|
1128
|
+
}
|
|
1129
|
+
process2.kill(process2.pid, sig);
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
});
|
|
1133
|
+
module.exports.signals = function() {
|
|
1134
|
+
return signals;
|
|
1135
|
+
};
|
|
1136
|
+
loaded = false;
|
|
1137
|
+
load = function load2() {
|
|
1138
|
+
if (loaded || !processOk(global.process)) {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
loaded = true;
|
|
1142
|
+
emitter.count += 1;
|
|
1143
|
+
signals = signals.filter(function(sig) {
|
|
1144
|
+
try {
|
|
1145
|
+
process2.on(sig, sigListeners[sig]);
|
|
1146
|
+
return true;
|
|
1147
|
+
} catch (er) {
|
|
1148
|
+
return false;
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
process2.emit = processEmit;
|
|
1152
|
+
process2.reallyExit = processReallyExit;
|
|
1153
|
+
};
|
|
1154
|
+
module.exports.load = load;
|
|
1155
|
+
originalProcessReallyExit = process2.reallyExit;
|
|
1156
|
+
processReallyExit = function processReallyExit2(code) {
|
|
1157
|
+
if (!processOk(global.process)) {
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
process2.exitCode = code || 0;
|
|
1161
|
+
emit("exit", process2.exitCode, null);
|
|
1162
|
+
emit("afterexit", process2.exitCode, null);
|
|
1163
|
+
originalProcessReallyExit.call(process2, process2.exitCode);
|
|
1164
|
+
};
|
|
1165
|
+
originalProcessEmit = process2.emit;
|
|
1166
|
+
processEmit = function processEmit2(ev, arg) {
|
|
1167
|
+
if (ev === "exit" && processOk(global.process)) {
|
|
1168
|
+
if (arg !== undefined) {
|
|
1169
|
+
process2.exitCode = arg;
|
|
1170
|
+
}
|
|
1171
|
+
var ret = originalProcessEmit.apply(this, arguments);
|
|
1172
|
+
emit("exit", process2.exitCode, null);
|
|
1173
|
+
emit("afterexit", process2.exitCode, null);
|
|
1174
|
+
return ret;
|
|
1175
|
+
} else {
|
|
1176
|
+
return originalProcessEmit.apply(this, arguments);
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
var assert;
|
|
1181
|
+
var signals;
|
|
1182
|
+
var isWin;
|
|
1183
|
+
var EE;
|
|
1184
|
+
var emitter;
|
|
1185
|
+
var unload;
|
|
1186
|
+
var emit;
|
|
1187
|
+
var sigListeners;
|
|
1188
|
+
var loaded;
|
|
1189
|
+
var load;
|
|
1190
|
+
var originalProcessReallyExit;
|
|
1191
|
+
var processReallyExit;
|
|
1192
|
+
var originalProcessEmit;
|
|
1193
|
+
var processEmit;
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
// node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/mtime-precision.js
|
|
1197
|
+
var require_mtime_precision = __commonJS((exports, module) => {
|
|
1198
|
+
var cacheSymbol = Symbol();
|
|
1199
|
+
function probe(file, fs, callback) {
|
|
1200
|
+
const cachedPrecision = fs[cacheSymbol];
|
|
1201
|
+
if (cachedPrecision) {
|
|
1202
|
+
return fs.stat(file, (err, stat) => {
|
|
1203
|
+
if (err) {
|
|
1204
|
+
return callback(err);
|
|
1205
|
+
}
|
|
1206
|
+
callback(null, stat.mtime, cachedPrecision);
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
const mtime = new Date(Math.ceil(Date.now() / 1000) * 1000 + 5);
|
|
1210
|
+
fs.utimes(file, mtime, mtime, (err) => {
|
|
1211
|
+
if (err) {
|
|
1212
|
+
return callback(err);
|
|
1213
|
+
}
|
|
1214
|
+
fs.stat(file, (err2, stat) => {
|
|
1215
|
+
if (err2) {
|
|
1216
|
+
return callback(err2);
|
|
1217
|
+
}
|
|
1218
|
+
const precision = stat.mtime.getTime() % 1000 === 0 ? "s" : "ms";
|
|
1219
|
+
Object.defineProperty(fs, cacheSymbol, { value: precision });
|
|
1220
|
+
callback(null, stat.mtime, precision);
|
|
1221
|
+
});
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
function getMtime(precision) {
|
|
1225
|
+
let now = Date.now();
|
|
1226
|
+
if (precision === "s") {
|
|
1227
|
+
now = Math.ceil(now / 1000) * 1000;
|
|
1228
|
+
}
|
|
1229
|
+
return new Date(now);
|
|
1230
|
+
}
|
|
1231
|
+
exports.probe = probe;
|
|
1232
|
+
exports.getMtime = getMtime;
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
// node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/lockfile.js
|
|
1236
|
+
var require_lockfile = __commonJS((exports, module) => {
|
|
1237
|
+
var path = __require("path");
|
|
1238
|
+
var fs = require_graceful_fs();
|
|
1239
|
+
var retry = require_retry();
|
|
1240
|
+
var onExit = require_signal_exit();
|
|
1241
|
+
var mtimePrecision = require_mtime_precision();
|
|
1242
|
+
var locks = {};
|
|
1243
|
+
function getLockFile(file, options) {
|
|
1244
|
+
return options.lockfilePath || `${file}.lock`;
|
|
1245
|
+
}
|
|
1246
|
+
function resolveCanonicalPath(file, options, callback) {
|
|
1247
|
+
if (!options.realpath) {
|
|
1248
|
+
return callback(null, path.resolve(file));
|
|
1249
|
+
}
|
|
1250
|
+
options.fs.realpath(file, callback);
|
|
1251
|
+
}
|
|
1252
|
+
function acquireLock(file, options, callback) {
|
|
1253
|
+
const lockfilePath = getLockFile(file, options);
|
|
1254
|
+
options.fs.mkdir(lockfilePath, (err) => {
|
|
1255
|
+
if (!err) {
|
|
1256
|
+
return mtimePrecision.probe(lockfilePath, options.fs, (err2, mtime, mtimePrecision2) => {
|
|
1257
|
+
if (err2) {
|
|
1258
|
+
options.fs.rmdir(lockfilePath, () => {});
|
|
1259
|
+
return callback(err2);
|
|
1260
|
+
}
|
|
1261
|
+
callback(null, mtime, mtimePrecision2);
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
if (err.code !== "EEXIST") {
|
|
1265
|
+
return callback(err);
|
|
1266
|
+
}
|
|
1267
|
+
if (options.stale <= 0) {
|
|
1268
|
+
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
1269
|
+
}
|
|
1270
|
+
options.fs.stat(lockfilePath, (err2, stat) => {
|
|
1271
|
+
if (err2) {
|
|
1272
|
+
if (err2.code === "ENOENT") {
|
|
1273
|
+
return acquireLock(file, { ...options, stale: 0 }, callback);
|
|
1274
|
+
}
|
|
1275
|
+
return callback(err2);
|
|
1276
|
+
}
|
|
1277
|
+
if (!isLockStale(stat, options)) {
|
|
1278
|
+
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
|
|
1279
|
+
}
|
|
1280
|
+
removeLock(file, options, (err3) => {
|
|
1281
|
+
if (err3) {
|
|
1282
|
+
return callback(err3);
|
|
1283
|
+
}
|
|
1284
|
+
acquireLock(file, { ...options, stale: 0 }, callback);
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
function isLockStale(stat, options) {
|
|
1290
|
+
return stat.mtime.getTime() < Date.now() - options.stale;
|
|
1291
|
+
}
|
|
1292
|
+
function removeLock(file, options, callback) {
|
|
1293
|
+
options.fs.rmdir(getLockFile(file, options), (err) => {
|
|
1294
|
+
if (err && err.code !== "ENOENT") {
|
|
1295
|
+
return callback(err);
|
|
1296
|
+
}
|
|
1297
|
+
callback();
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
function updateLock(file, options) {
|
|
1301
|
+
const lock2 = locks[file];
|
|
1302
|
+
if (lock2.updateTimeout) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
lock2.updateDelay = lock2.updateDelay || options.update;
|
|
1306
|
+
lock2.updateTimeout = setTimeout(() => {
|
|
1307
|
+
lock2.updateTimeout = null;
|
|
1308
|
+
options.fs.stat(lock2.lockfilePath, (err, stat) => {
|
|
1309
|
+
const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
|
|
1310
|
+
if (err) {
|
|
1311
|
+
if (err.code === "ENOENT" || isOverThreshold) {
|
|
1312
|
+
return setLockAsCompromised(file, lock2, Object.assign(err, { code: "ECOMPROMISED" }));
|
|
1313
|
+
}
|
|
1314
|
+
lock2.updateDelay = 1000;
|
|
1315
|
+
return updateLock(file, options);
|
|
1316
|
+
}
|
|
1317
|
+
const isMtimeOurs = lock2.mtime.getTime() === stat.mtime.getTime();
|
|
1318
|
+
if (!isMtimeOurs) {
|
|
1319
|
+
return setLockAsCompromised(file, lock2, Object.assign(new Error("Unable to update lock within the stale threshold"), { code: "ECOMPROMISED" }));
|
|
1320
|
+
}
|
|
1321
|
+
const mtime = mtimePrecision.getMtime(lock2.mtimePrecision);
|
|
1322
|
+
options.fs.utimes(lock2.lockfilePath, mtime, mtime, (err2) => {
|
|
1323
|
+
const isOverThreshold2 = lock2.lastUpdate + options.stale < Date.now();
|
|
1324
|
+
if (lock2.released) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (err2) {
|
|
1328
|
+
if (err2.code === "ENOENT" || isOverThreshold2) {
|
|
1329
|
+
return setLockAsCompromised(file, lock2, Object.assign(err2, { code: "ECOMPROMISED" }));
|
|
1330
|
+
}
|
|
1331
|
+
lock2.updateDelay = 1000;
|
|
1332
|
+
return updateLock(file, options);
|
|
1333
|
+
}
|
|
1334
|
+
lock2.mtime = mtime;
|
|
1335
|
+
lock2.lastUpdate = Date.now();
|
|
1336
|
+
lock2.updateDelay = null;
|
|
1337
|
+
updateLock(file, options);
|
|
1338
|
+
});
|
|
1339
|
+
});
|
|
1340
|
+
}, lock2.updateDelay);
|
|
1341
|
+
if (lock2.updateTimeout.unref) {
|
|
1342
|
+
lock2.updateTimeout.unref();
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
function setLockAsCompromised(file, lock2, err) {
|
|
1346
|
+
lock2.released = true;
|
|
1347
|
+
if (lock2.updateTimeout) {
|
|
1348
|
+
clearTimeout(lock2.updateTimeout);
|
|
1349
|
+
}
|
|
1350
|
+
if (locks[file] === lock2) {
|
|
1351
|
+
delete locks[file];
|
|
1352
|
+
}
|
|
1353
|
+
lock2.options.onCompromised(err);
|
|
1354
|
+
}
|
|
1355
|
+
function lock(file, options, callback) {
|
|
1356
|
+
options = {
|
|
1357
|
+
stale: 1e4,
|
|
1358
|
+
update: null,
|
|
1359
|
+
realpath: true,
|
|
1360
|
+
retries: 0,
|
|
1361
|
+
fs,
|
|
1362
|
+
onCompromised: (err) => {
|
|
1363
|
+
throw err;
|
|
1364
|
+
},
|
|
1365
|
+
...options
|
|
1366
|
+
};
|
|
1367
|
+
options.retries = options.retries || 0;
|
|
1368
|
+
options.retries = typeof options.retries === "number" ? { retries: options.retries } : options.retries;
|
|
1369
|
+
options.stale = Math.max(options.stale || 0, 2000);
|
|
1370
|
+
options.update = options.update == null ? options.stale / 2 : options.update || 0;
|
|
1371
|
+
options.update = Math.max(Math.min(options.update, options.stale / 2), 1000);
|
|
1372
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
1373
|
+
if (err) {
|
|
1374
|
+
return callback(err);
|
|
1375
|
+
}
|
|
1376
|
+
const operation = retry.operation(options.retries);
|
|
1377
|
+
operation.attempt(() => {
|
|
1378
|
+
acquireLock(file2, options, (err2, mtime, mtimePrecision2) => {
|
|
1379
|
+
if (operation.retry(err2)) {
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
if (err2) {
|
|
1383
|
+
return callback(operation.mainError());
|
|
1384
|
+
}
|
|
1385
|
+
const lock2 = locks[file2] = {
|
|
1386
|
+
lockfilePath: getLockFile(file2, options),
|
|
1387
|
+
mtime,
|
|
1388
|
+
mtimePrecision: mtimePrecision2,
|
|
1389
|
+
options,
|
|
1390
|
+
lastUpdate: Date.now()
|
|
1391
|
+
};
|
|
1392
|
+
updateLock(file2, options);
|
|
1393
|
+
callback(null, (releasedCallback) => {
|
|
1394
|
+
if (lock2.released) {
|
|
1395
|
+
return releasedCallback && releasedCallback(Object.assign(new Error("Lock is already released"), { code: "ERELEASED" }));
|
|
1396
|
+
}
|
|
1397
|
+
unlock(file2, { ...options, realpath: false }, releasedCallback);
|
|
1398
|
+
});
|
|
1399
|
+
});
|
|
1400
|
+
});
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
function unlock(file, options, callback) {
|
|
1404
|
+
options = {
|
|
1405
|
+
fs,
|
|
1406
|
+
realpath: true,
|
|
1407
|
+
...options
|
|
1408
|
+
};
|
|
1409
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
1410
|
+
if (err) {
|
|
1411
|
+
return callback(err);
|
|
1412
|
+
}
|
|
1413
|
+
const lock2 = locks[file2];
|
|
1414
|
+
if (!lock2) {
|
|
1415
|
+
return callback(Object.assign(new Error("Lock is not acquired/owned by you"), { code: "ENOTACQUIRED" }));
|
|
1416
|
+
}
|
|
1417
|
+
lock2.updateTimeout && clearTimeout(lock2.updateTimeout);
|
|
1418
|
+
lock2.released = true;
|
|
1419
|
+
delete locks[file2];
|
|
1420
|
+
removeLock(file2, options, callback);
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
function check(file, options, callback) {
|
|
1424
|
+
options = {
|
|
1425
|
+
stale: 1e4,
|
|
1426
|
+
realpath: true,
|
|
1427
|
+
fs,
|
|
1428
|
+
...options
|
|
1429
|
+
};
|
|
1430
|
+
options.stale = Math.max(options.stale || 0, 2000);
|
|
1431
|
+
resolveCanonicalPath(file, options, (err, file2) => {
|
|
1432
|
+
if (err) {
|
|
1433
|
+
return callback(err);
|
|
1434
|
+
}
|
|
1435
|
+
options.fs.stat(getLockFile(file2, options), (err2, stat) => {
|
|
1436
|
+
if (err2) {
|
|
1437
|
+
return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
|
|
1438
|
+
}
|
|
1439
|
+
return callback(null, !isLockStale(stat, options));
|
|
1440
|
+
});
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
function getLocks() {
|
|
1444
|
+
return locks;
|
|
1445
|
+
}
|
|
1446
|
+
onExit(() => {
|
|
1447
|
+
for (const file in locks) {
|
|
1448
|
+
const options = locks[file].options;
|
|
1449
|
+
try {
|
|
1450
|
+
options.fs.rmdirSync(getLockFile(file, options));
|
|
1451
|
+
} catch (e) {}
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
exports.lock = lock;
|
|
1455
|
+
exports.unlock = unlock;
|
|
1456
|
+
exports.check = check;
|
|
1457
|
+
exports.getLocks = getLocks;
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
// node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/adapter.js
|
|
1461
|
+
var require_adapter = __commonJS((exports, module) => {
|
|
1462
|
+
var fs = require_graceful_fs();
|
|
1463
|
+
function createSyncFs(fs2) {
|
|
1464
|
+
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
|
|
1465
|
+
const newFs = { ...fs2 };
|
|
1466
|
+
methods.forEach((method) => {
|
|
1467
|
+
newFs[method] = (...args) => {
|
|
1468
|
+
const callback = args.pop();
|
|
1469
|
+
let ret;
|
|
1470
|
+
try {
|
|
1471
|
+
ret = fs2[`${method}Sync`](...args);
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
return callback(err);
|
|
1474
|
+
}
|
|
1475
|
+
callback(null, ret);
|
|
1476
|
+
};
|
|
1477
|
+
});
|
|
1478
|
+
return newFs;
|
|
1479
|
+
}
|
|
1480
|
+
function toPromise(method) {
|
|
1481
|
+
return (...args) => new Promise((resolve, reject) => {
|
|
1482
|
+
args.push((err, result) => {
|
|
1483
|
+
if (err) {
|
|
1484
|
+
reject(err);
|
|
1485
|
+
} else {
|
|
1486
|
+
resolve(result);
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
method(...args);
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
function toSync(method) {
|
|
1493
|
+
return (...args) => {
|
|
1494
|
+
let err;
|
|
1495
|
+
let result;
|
|
1496
|
+
args.push((_err, _result) => {
|
|
1497
|
+
err = _err;
|
|
1498
|
+
result = _result;
|
|
1499
|
+
});
|
|
1500
|
+
method(...args);
|
|
1501
|
+
if (err) {
|
|
1502
|
+
throw err;
|
|
1503
|
+
}
|
|
1504
|
+
return result;
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
function toSyncOptions(options) {
|
|
1508
|
+
options = { ...options };
|
|
1509
|
+
options.fs = createSyncFs(options.fs || fs);
|
|
1510
|
+
if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
|
|
1511
|
+
throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
|
|
1512
|
+
}
|
|
1513
|
+
return options;
|
|
1514
|
+
}
|
|
1515
|
+
module.exports = {
|
|
1516
|
+
toPromise,
|
|
1517
|
+
toSync,
|
|
1518
|
+
toSyncOptions
|
|
1519
|
+
};
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
// node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/index.js
|
|
1523
|
+
var require_proper_lockfile = __commonJS((exports, module) => {
|
|
1524
|
+
var lockfile = require_lockfile();
|
|
1525
|
+
var { toPromise, toSync, toSyncOptions } = require_adapter();
|
|
1526
|
+
async function lock(file, options) {
|
|
1527
|
+
const release = await toPromise(lockfile.lock)(file, options);
|
|
1528
|
+
return toPromise(release);
|
|
1529
|
+
}
|
|
1530
|
+
function lockSync(file, options) {
|
|
1531
|
+
const release = toSync(lockfile.lock)(file, toSyncOptions(options));
|
|
1532
|
+
return toSync(release);
|
|
1533
|
+
}
|
|
1534
|
+
function unlock(file, options) {
|
|
1535
|
+
return toPromise(lockfile.unlock)(file, options);
|
|
1536
|
+
}
|
|
1537
|
+
function unlockSync(file, options) {
|
|
1538
|
+
return toSync(lockfile.unlock)(file, toSyncOptions(options));
|
|
1539
|
+
}
|
|
1540
|
+
function check(file, options) {
|
|
1541
|
+
return toPromise(lockfile.check)(file, options);
|
|
1542
|
+
}
|
|
1543
|
+
function checkSync(file, options) {
|
|
1544
|
+
return toSync(lockfile.check)(file, toSyncOptions(options));
|
|
1545
|
+
}
|
|
1546
|
+
module.exports = lock;
|
|
1547
|
+
module.exports.lock = lock;
|
|
1548
|
+
module.exports.unlock = unlock;
|
|
1549
|
+
module.exports.lockSync = lockSync;
|
|
1550
|
+
module.exports.unlockSync = unlockSync;
|
|
1551
|
+
module.exports.check = check;
|
|
1552
|
+
module.exports.checkSync = checkSync;
|
|
1553
|
+
});
|
|
1554
|
+
|
|
1555
|
+
// src/tui.tsx
|
|
1556
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
1557
|
+
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
1558
|
+
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
1559
|
+
import { setProp as _$setProp } from "@opentui/solid";
|
|
1560
|
+
import { effect as _$effect } from "@opentui/solid";
|
|
1561
|
+
import { insert as _$insert } from "@opentui/solid";
|
|
1562
|
+
import { createElement as _$createElement } from "@opentui/solid";
|
|
1563
|
+
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
1564
|
+
import { TextAttributes } from "@opentui/core";
|
|
1565
|
+
import { createSignal, onCleanup } from "solid-js";
|
|
1566
|
+
|
|
1567
|
+
// src/github.ts
|
|
1568
|
+
import { execFile } from "child_process";
|
|
1569
|
+
|
|
1570
|
+
// src/exhaustive.ts
|
|
1571
|
+
function casesHandled(value) {
|
|
1572
|
+
throw new Error(`Unhandled case: ${String(value)}`);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// src/url.ts
|
|
1576
|
+
var invalidPullRequestUrl = {
|
|
1577
|
+
ok: false,
|
|
1578
|
+
error: {
|
|
1579
|
+
tag: "InvalidPullRequestUrl",
|
|
1580
|
+
message: "Expected https://github.com/<owner>/<repository>/pull/<positive-integer>"
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
var segmentPattern = /^[A-Za-z0-9._-]+$/;
|
|
1584
|
+
function parsePullRequestUrl(input) {
|
|
1585
|
+
if (input.trim() !== input)
|
|
1586
|
+
return invalidPullRequestUrl;
|
|
1587
|
+
if (!input.startsWith("https://"))
|
|
1588
|
+
return invalidPullRequestUrl;
|
|
1589
|
+
const authorityEnd = input.indexOf("/", "https://".length);
|
|
1590
|
+
if (authorityEnd === -1)
|
|
1591
|
+
return invalidPullRequestUrl;
|
|
1592
|
+
if (input.slice("https://".length, authorityEnd).toLowerCase() !== "github.com") {
|
|
1593
|
+
return invalidPullRequestUrl;
|
|
1594
|
+
}
|
|
1595
|
+
const rawPath = input.slice(authorityEnd).split(/[?#]/, 1).join("");
|
|
1596
|
+
for (const segment of rawPath.split("/")) {
|
|
1597
|
+
let decoded;
|
|
1598
|
+
try {
|
|
1599
|
+
decoded = decodeURIComponent(segment);
|
|
1600
|
+
} catch {
|
|
1601
|
+
return invalidPullRequestUrl;
|
|
1602
|
+
}
|
|
1603
|
+
if (decoded === "." || decoded === "..")
|
|
1604
|
+
return invalidPullRequestUrl;
|
|
1605
|
+
}
|
|
1606
|
+
let parsed;
|
|
1607
|
+
try {
|
|
1608
|
+
parsed = new URL(input);
|
|
1609
|
+
} catch {
|
|
1610
|
+
return invalidPullRequestUrl;
|
|
1611
|
+
}
|
|
1612
|
+
if (parsed.protocol !== "https:" || parsed.hostname !== "github.com" || parsed.username !== "" || parsed.password !== "" || parsed.port !== "" || parsed.search !== "" || parsed.hash !== "") {
|
|
1613
|
+
return invalidPullRequestUrl;
|
|
1614
|
+
}
|
|
1615
|
+
const segments = parsed.pathname.split("/");
|
|
1616
|
+
if (segments.length !== 5 || segments[0] !== "" || segments[3] !== "pull") {
|
|
1617
|
+
return invalidPullRequestUrl;
|
|
1618
|
+
}
|
|
1619
|
+
const owner = segments[1];
|
|
1620
|
+
const repository = segments[2];
|
|
1621
|
+
const numberText = segments[4];
|
|
1622
|
+
if (owner === undefined || repository === undefined || numberText === undefined || !segmentPattern.test(owner) || !segmentPattern.test(repository) || !/^\d+$/.test(numberText)) {
|
|
1623
|
+
return invalidPullRequestUrl;
|
|
1624
|
+
}
|
|
1625
|
+
const number = Number(numberText);
|
|
1626
|
+
if (!Number.isSafeInteger(number) || number <= 0)
|
|
1627
|
+
return invalidPullRequestUrl;
|
|
1628
|
+
const url = `https://github.com/${owner}/${repository}/pull/${number}`;
|
|
1629
|
+
const value = { url, owner, repository, number };
|
|
1630
|
+
return { ok: true, value };
|
|
1631
|
+
}
|
|
1632
|
+
function formatPullRequestRef(pullRequest) {
|
|
1633
|
+
return `${pullRequest.owner}/${pullRequest.repository}#${pullRequest.number}`;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
// src/github.ts
|
|
1637
|
+
var invalidGitHubResponse = {
|
|
1638
|
+
ok: false,
|
|
1639
|
+
error: {
|
|
1640
|
+
tag: "InvalidGitHubResponse",
|
|
1641
|
+
message: "GitHub returned an invalid pull request response"
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
var githubBatchLimitExceeded = {
|
|
1645
|
+
ok: false,
|
|
1646
|
+
error: {
|
|
1647
|
+
tag: "GitHubBatchLimitExceeded",
|
|
1648
|
+
limit: 20,
|
|
1649
|
+
message: "GitHub batch cannot contain more than 20 pull requests"
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
var checkRunPending = new Set(["QUEUED", "IN_PROGRESS", "WAITING", "PENDING"]);
|
|
1653
|
+
var checkRunPassed = new Set(["SUCCESS"]);
|
|
1654
|
+
var checkRunFailed = new Set(["FAILURE", "CANCELLED", "TIMED_OUT", "ACTION_REQUIRED", "STARTUP_FAILURE", "STALE"]);
|
|
1655
|
+
var checkRunIgnored = new Set(["NEUTRAL", "SKIPPED"]);
|
|
1656
|
+
var statusContextPending = new Set(["EXPECTED", "PENDING"]);
|
|
1657
|
+
var statusContextPassed = new Set(["SUCCESS"]);
|
|
1658
|
+
var statusContextFailed = new Set(["ERROR", "FAILURE"]);
|
|
1659
|
+
var maximumPullRequestsPerBatch = 20;
|
|
1660
|
+
var pullRequestSelection = `__typename ... on PullRequest { title state url mergedAt mergeable statusCheckRollup { contexts(first: 1) { checkRunCount statusContextCount checkRunCountsByState { state count } statusContextCountsByState { state count } } } }`;
|
|
1661
|
+
function isRecord(value) {
|
|
1662
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1663
|
+
}
|
|
1664
|
+
function parseProcessExecutionFailed(value) {
|
|
1665
|
+
if (!isRecord(value) || value.tag !== "ProcessExecutionFailed" || value.code !== null && typeof value.code !== "string" && typeof value.code !== "number" || typeof value.stderr !== "string" || typeof value.stdout !== "string" || !("cause" in value)) {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
return {
|
|
1669
|
+
tag: "ProcessExecutionFailed",
|
|
1670
|
+
code: value.code,
|
|
1671
|
+
stderr: value.stderr,
|
|
1672
|
+
stdout: value.stdout,
|
|
1673
|
+
cause: value.cause
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
function classifyCountState(state, states) {
|
|
1677
|
+
if (states.failed.has(state))
|
|
1678
|
+
return "failed";
|
|
1679
|
+
if (states.pending.has(state))
|
|
1680
|
+
return "pending";
|
|
1681
|
+
if (states.passed.has(state))
|
|
1682
|
+
return "passed";
|
|
1683
|
+
if (states.ignored?.has(state))
|
|
1684
|
+
return "ignored";
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
function aggregateCounts(input, expectedTotal, states) {
|
|
1688
|
+
if (!Array.isArray(input) || !Number.isInteger(expectedTotal) || Number(expectedTotal) < 0) {
|
|
1689
|
+
return invalidGitHubResponse;
|
|
1690
|
+
}
|
|
1691
|
+
const buckets = new Set;
|
|
1692
|
+
const seenStates = new Set;
|
|
1693
|
+
let total = 0;
|
|
1694
|
+
for (const item of input) {
|
|
1695
|
+
if (!isRecord(item) || typeof item.state !== "string" || !Number.isInteger(item.count) || Number(item.count) < 0 || seenStates.has(item.state)) {
|
|
1696
|
+
return invalidGitHubResponse;
|
|
1697
|
+
}
|
|
1698
|
+
const bucket = classifyCountState(item.state, states);
|
|
1699
|
+
if (bucket === undefined && Number(item.count) > 0)
|
|
1700
|
+
return invalidGitHubResponse;
|
|
1701
|
+
seenStates.add(item.state);
|
|
1702
|
+
total += Number(item.count);
|
|
1703
|
+
if (bucket !== undefined && Number(item.count) > 0)
|
|
1704
|
+
buckets.add(bucket);
|
|
1705
|
+
}
|
|
1706
|
+
return total === expectedTotal ? { ok: true, value: buckets } : invalidGitHubResponse;
|
|
1707
|
+
}
|
|
1708
|
+
function parseStatusCheckRollup(input) {
|
|
1709
|
+
if (input === null)
|
|
1710
|
+
return { ok: true, value: "none" };
|
|
1711
|
+
if (!isRecord(input) || !isRecord(input.contexts))
|
|
1712
|
+
return invalidGitHubResponse;
|
|
1713
|
+
const contexts = input.contexts;
|
|
1714
|
+
const checkRuns = aggregateCounts(contexts.checkRunCountsByState, contexts.checkRunCount, {
|
|
1715
|
+
passed: checkRunPassed,
|
|
1716
|
+
pending: checkRunPending,
|
|
1717
|
+
failed: checkRunFailed,
|
|
1718
|
+
ignored: checkRunIgnored
|
|
1719
|
+
});
|
|
1720
|
+
if (!checkRuns.ok)
|
|
1721
|
+
return checkRuns;
|
|
1722
|
+
const statusContexts = aggregateCounts(contexts.statusContextCountsByState, contexts.statusContextCount, {
|
|
1723
|
+
passed: statusContextPassed,
|
|
1724
|
+
pending: statusContextPending,
|
|
1725
|
+
failed: statusContextFailed
|
|
1726
|
+
});
|
|
1727
|
+
if (!statusContexts.ok)
|
|
1728
|
+
return statusContexts;
|
|
1729
|
+
const buckets = new Set([...checkRuns.value, ...statusContexts.value]);
|
|
1730
|
+
if (buckets.has("failed"))
|
|
1731
|
+
return { ok: true, value: "failed" };
|
|
1732
|
+
if (buckets.has("pending"))
|
|
1733
|
+
return { ok: true, value: "pending" };
|
|
1734
|
+
if (buckets.has("passed"))
|
|
1735
|
+
return { ok: true, value: "passed" };
|
|
1736
|
+
return { ok: true, value: "none" };
|
|
1737
|
+
}
|
|
1738
|
+
function samePullRequest(left, right) {
|
|
1739
|
+
return left.number === right.number && left.owner.toLowerCase() === right.owner.toLowerCase() && left.repository.toLowerCase() === right.repository.toLowerCase();
|
|
1740
|
+
}
|
|
1741
|
+
function parseMergeability(input) {
|
|
1742
|
+
switch (input) {
|
|
1743
|
+
case "MERGEABLE":
|
|
1744
|
+
return { ok: true, value: "mergeable" };
|
|
1745
|
+
case "CONFLICTING":
|
|
1746
|
+
return { ok: true, value: "conflicting" };
|
|
1747
|
+
case "UNKNOWN":
|
|
1748
|
+
return { ok: true, value: "unknown" };
|
|
1749
|
+
default:
|
|
1750
|
+
return invalidGitHubResponse;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
function parseResponse(input, pullRequest) {
|
|
1754
|
+
if (!isRecord(input) || input.__typename !== "PullRequest" || typeof input.title !== "string" || input.title.trim() === "") {
|
|
1755
|
+
return invalidGitHubResponse;
|
|
1756
|
+
}
|
|
1757
|
+
if (input.state !== "OPEN" && input.state !== "CLOSED" && input.state !== "MERGED") {
|
|
1758
|
+
return invalidGitHubResponse;
|
|
1759
|
+
}
|
|
1760
|
+
if (input.mergedAt !== null && typeof input.mergedAt !== "string")
|
|
1761
|
+
return invalidGitHubResponse;
|
|
1762
|
+
if (typeof input.mergedAt === "string" && Number.isNaN(new Date(input.mergedAt).valueOf())) {
|
|
1763
|
+
return invalidGitHubResponse;
|
|
1764
|
+
}
|
|
1765
|
+
if (input.state === "MERGED" && typeof input.mergedAt !== "string")
|
|
1766
|
+
return invalidGitHubResponse;
|
|
1767
|
+
if (input.state !== "MERGED" && input.mergedAt !== null)
|
|
1768
|
+
return invalidGitHubResponse;
|
|
1769
|
+
if (typeof input.url !== "string")
|
|
1770
|
+
return invalidGitHubResponse;
|
|
1771
|
+
const responseUrl = parsePullRequestUrl(input.url);
|
|
1772
|
+
if (!responseUrl.ok || !samePullRequest(responseUrl.value, pullRequest))
|
|
1773
|
+
return invalidGitHubResponse;
|
|
1774
|
+
const ci = parseStatusCheckRollup(input.statusCheckRollup);
|
|
1775
|
+
if (!ci.ok)
|
|
1776
|
+
return ci;
|
|
1777
|
+
const mergeability = parseMergeability(input.mergeable);
|
|
1778
|
+
if (!mergeability.ok)
|
|
1779
|
+
return mergeability;
|
|
1780
|
+
let state;
|
|
1781
|
+
switch (input.state) {
|
|
1782
|
+
case "OPEN":
|
|
1783
|
+
state = { tag: "Open", ci: ci.value, mergeability: mergeability.value };
|
|
1784
|
+
break;
|
|
1785
|
+
case "MERGED":
|
|
1786
|
+
state = { tag: "Merged" };
|
|
1787
|
+
break;
|
|
1788
|
+
case "CLOSED":
|
|
1789
|
+
state = { tag: "Closed" };
|
|
1790
|
+
break;
|
|
1791
|
+
default:
|
|
1792
|
+
return casesHandled(input.state);
|
|
1793
|
+
}
|
|
1794
|
+
return {
|
|
1795
|
+
ok: true,
|
|
1796
|
+
value: {
|
|
1797
|
+
tag: "Available",
|
|
1798
|
+
pullRequest,
|
|
1799
|
+
title: input.title,
|
|
1800
|
+
state,
|
|
1801
|
+
stale: false
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
function createBatchQuery(size) {
|
|
1806
|
+
const variables = Array.from({ length: size }, (_, index) => `$url${index}: URI!`).join(", ");
|
|
1807
|
+
const fields = Array.from({ length: size }, (_, index) => `pr${index}: resource(url: $url${index}) { ${pullRequestSelection} }`).join(" ");
|
|
1808
|
+
return `query BatchPullRequests(${variables}) { ${fields} }`;
|
|
1809
|
+
}
|
|
1810
|
+
function parseGraphqlErrorAliases(input, size) {
|
|
1811
|
+
if (input === undefined)
|
|
1812
|
+
return { ok: true, value: new Set };
|
|
1813
|
+
if (!Array.isArray(input))
|
|
1814
|
+
return invalidGitHubResponse;
|
|
1815
|
+
const aliases = new Set;
|
|
1816
|
+
for (const error of input) {
|
|
1817
|
+
if (!isRecord(error) || typeof error.message !== "string" || !Array.isArray(error.path) || typeof error.path[0] !== "string") {
|
|
1818
|
+
return invalidGitHubResponse;
|
|
1819
|
+
}
|
|
1820
|
+
const match = /^pr([0-9]+)$/.exec(error.path[0]);
|
|
1821
|
+
if (match === null)
|
|
1822
|
+
return invalidGitHubResponse;
|
|
1823
|
+
const index = Number(match[1]);
|
|
1824
|
+
if (!Number.isInteger(index) || index < 0 || index >= size)
|
|
1825
|
+
return invalidGitHubResponse;
|
|
1826
|
+
aliases.add(index);
|
|
1827
|
+
}
|
|
1828
|
+
return { ok: true, value: aliases };
|
|
1829
|
+
}
|
|
1830
|
+
function parseBatchResponse(input, pullRequests) {
|
|
1831
|
+
if (!isRecord(input) || !isRecord(input.data))
|
|
1832
|
+
return invalidGitHubResponse;
|
|
1833
|
+
const data = input.data;
|
|
1834
|
+
const errorAliases = parseGraphqlErrorAliases(input.errors, pullRequests.length);
|
|
1835
|
+
if (!errorAliases.ok)
|
|
1836
|
+
return errorAliases;
|
|
1837
|
+
return {
|
|
1838
|
+
ok: true,
|
|
1839
|
+
value: pullRequests.map((pullRequest, index) => errorAliases.value.has(index) ? invalidGitHubResponse : parseResponse(data[`pr${index}`], pullRequest))
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
function isCancellation(cause, signal) {
|
|
1843
|
+
if (signal?.aborted)
|
|
1844
|
+
return true;
|
|
1845
|
+
const originalCause = parseProcessExecutionFailed(cause)?.cause ?? cause;
|
|
1846
|
+
return originalCause instanceof Error && originalCause.name === "AbortError";
|
|
1847
|
+
}
|
|
1848
|
+
var authenticationFailureMarkers = ["http 401", "bad credentials", "not logged into", "gh auth login"];
|
|
1849
|
+
function isAuthenticationFailure(failure) {
|
|
1850
|
+
if (failure.code === 4)
|
|
1851
|
+
return true;
|
|
1852
|
+
const stderr = failure.stderr.toLowerCase();
|
|
1853
|
+
return authenticationFailureMarkers.some((marker) => stderr.includes(marker));
|
|
1854
|
+
}
|
|
1855
|
+
function classifyProcessFailure(cause) {
|
|
1856
|
+
const failure = parseProcessExecutionFailed(cause);
|
|
1857
|
+
if (failure?.code === "ENOENT") {
|
|
1858
|
+
return { tag: "GitHubCliMissing", message: "GitHub CLI is not installed", cause };
|
|
1859
|
+
}
|
|
1860
|
+
if (failure && isAuthenticationFailure(failure)) {
|
|
1861
|
+
return { tag: "GitHubAuthenticationRequired", message: "GitHub CLI authentication required", cause };
|
|
1862
|
+
}
|
|
1863
|
+
return { tag: "GitHubUnavailable", message: "GitHub status unavailable", cause };
|
|
1864
|
+
}
|
|
1865
|
+
function processFailureStdout(cause) {
|
|
1866
|
+
if (!isRecord(cause) || typeof cause.stdout !== "string" || cause.stdout.trim() === "")
|
|
1867
|
+
return;
|
|
1868
|
+
return cause.stdout;
|
|
1869
|
+
}
|
|
1870
|
+
var execFileRunner = (file, args, options) => new Promise((resolve, reject) => {
|
|
1871
|
+
execFile(file, [...args], {
|
|
1872
|
+
encoding: "utf8",
|
|
1873
|
+
...options.signal ? { signal: options.signal } : {},
|
|
1874
|
+
...options.cwd ? { cwd: options.cwd } : {}
|
|
1875
|
+
}, (error, stdout, stderr) => {
|
|
1876
|
+
if (error) {
|
|
1877
|
+
reject({
|
|
1878
|
+
tag: "ProcessExecutionFailed",
|
|
1879
|
+
code: error.code ?? null,
|
|
1880
|
+
stderr,
|
|
1881
|
+
stdout,
|
|
1882
|
+
cause: error
|
|
1883
|
+
});
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
resolve({ stdout });
|
|
1887
|
+
});
|
|
1888
|
+
});
|
|
1889
|
+
function createGitHubClient(runner = execFileRunner) {
|
|
1890
|
+
return {
|
|
1891
|
+
async get(pullRequests, options = {}) {
|
|
1892
|
+
if (pullRequests.length === 0)
|
|
1893
|
+
return { ok: true, value: [] };
|
|
1894
|
+
if (pullRequests.length > maximumPullRequestsPerBatch)
|
|
1895
|
+
return githubBatchLimitExceeded;
|
|
1896
|
+
const query = createBatchQuery(pullRequests.length);
|
|
1897
|
+
const args = ["api", "graphql", "--method", "POST", "-f", `query=${query}`];
|
|
1898
|
+
for (const [index, pullRequest] of pullRequests.entries()) {
|
|
1899
|
+
args.push("-f", `url${index}=${pullRequest.url}`);
|
|
1900
|
+
}
|
|
1901
|
+
let stdout;
|
|
1902
|
+
let processFailure;
|
|
1903
|
+
try {
|
|
1904
|
+
const output = await runner("gh", args, options);
|
|
1905
|
+
stdout = output.stdout;
|
|
1906
|
+
} catch (cause) {
|
|
1907
|
+
if (isCancellation(cause, options.signal)) {
|
|
1908
|
+
return {
|
|
1909
|
+
ok: false,
|
|
1910
|
+
error: {
|
|
1911
|
+
tag: "GitHubCancelled",
|
|
1912
|
+
message: "GitHub status request cancelled",
|
|
1913
|
+
cause
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
processFailure = classifyProcessFailure(cause);
|
|
1918
|
+
const partialStdout = processFailureStdout(cause);
|
|
1919
|
+
if (partialStdout !== undefined) {
|
|
1920
|
+
stdout = partialStdout;
|
|
1921
|
+
} else {
|
|
1922
|
+
return { ok: false, error: processFailure };
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
let decoded;
|
|
1926
|
+
try {
|
|
1927
|
+
decoded = JSON.parse(stdout);
|
|
1928
|
+
} catch {
|
|
1929
|
+
return processFailure === undefined ? invalidGitHubResponse : { ok: false, error: processFailure };
|
|
1930
|
+
}
|
|
1931
|
+
const parsed = parseBatchResponse(decoded, pullRequests);
|
|
1932
|
+
if (processFailure === undefined || parsed.ok)
|
|
1933
|
+
return parsed;
|
|
1934
|
+
return { ok: false, error: processFailure };
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
var openAppearances = {
|
|
1939
|
+
passed: { tone: "green", label: "checks passed", strikethrough: false },
|
|
1940
|
+
pending: { tone: "yellow", label: "checks pending", strikethrough: false },
|
|
1941
|
+
failed: { tone: "red", label: "checks failed", strikethrough: false },
|
|
1942
|
+
none: { tone: "gray", label: "no checks", strikethrough: false }
|
|
1943
|
+
};
|
|
1944
|
+
var diagnosticLabels = {
|
|
1945
|
+
GitHubCliMissing: "install gh",
|
|
1946
|
+
GitHubAuthenticationRequired: "run gh auth login",
|
|
1947
|
+
GitHubUnavailable: "GitHub unavailable",
|
|
1948
|
+
InvalidGitHubResponse: "invalid GitHub response"
|
|
1949
|
+
};
|
|
1950
|
+
function stateAppearance(state) {
|
|
1951
|
+
switch (state.tag) {
|
|
1952
|
+
case "Open": {
|
|
1953
|
+
switch (state.mergeability) {
|
|
1954
|
+
case "conflicting":
|
|
1955
|
+
return { tone: "red", label: "merge conflict", strikethrough: false };
|
|
1956
|
+
case "mergeable":
|
|
1957
|
+
case "unknown":
|
|
1958
|
+
return openAppearances[state.ci];
|
|
1959
|
+
default:
|
|
1960
|
+
return casesHandled(state.mergeability);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
case "Merged":
|
|
1964
|
+
return { tone: "purple", label: "merged", strikethrough: true };
|
|
1965
|
+
case "Closed":
|
|
1966
|
+
return { tone: "red", label: "closed", strikethrough: true };
|
|
1967
|
+
default:
|
|
1968
|
+
return casesHandled(state);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
function statusAppearance(status) {
|
|
1972
|
+
if (status.tag === "Unavailable") {
|
|
1973
|
+
return {
|
|
1974
|
+
tone: "gray",
|
|
1975
|
+
label: status.diagnostic === undefined ? "status unavailable" : diagnosticLabels[status.diagnostic],
|
|
1976
|
+
strikethrough: false
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1979
|
+
const appearance = stateAppearance(status.state);
|
|
1980
|
+
return status.stale ? { ...appearance, label: `${appearance.label} (stale; ${diagnosticLabels[status.diagnostic]})` } : appearance;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// src/attach.ts
|
|
1984
|
+
var invalidPullRequestInput = {
|
|
1985
|
+
ok: false,
|
|
1986
|
+
error: {
|
|
1987
|
+
tag: "InvalidPullRequestInput",
|
|
1988
|
+
message: "Expected https://github.com/<owner>/<repository>/pull/<positive-integer> or a positive pull request number"
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
var repositoryResolutionFailed = {
|
|
1992
|
+
tag: "RepositoryResolutionFailed",
|
|
1993
|
+
message: "Unable to resolve the current GitHub repository with gh; attach with a full URL instead"
|
|
1994
|
+
};
|
|
1995
|
+
var repositoryResolutionCancelled = {
|
|
1996
|
+
ok: false,
|
|
1997
|
+
error: { tag: "RepositoryResolutionCancelled" }
|
|
1998
|
+
};
|
|
1999
|
+
function isCancellation2(cause, signal) {
|
|
2000
|
+
if (signal?.aborted)
|
|
2001
|
+
return true;
|
|
2002
|
+
return cause instanceof Error && cause.name === "AbortError";
|
|
2003
|
+
}
|
|
2004
|
+
function parseRepositoryPullRequest(stdout, number) {
|
|
2005
|
+
let decoded;
|
|
2006
|
+
try {
|
|
2007
|
+
decoded = JSON.parse(stdout);
|
|
2008
|
+
} catch {
|
|
2009
|
+
return { ok: false, error: repositoryResolutionFailed };
|
|
2010
|
+
}
|
|
2011
|
+
if (decoded === null || typeof decoded !== "object" || !("url" in decoded) || typeof decoded.url !== "string" || decoded.url === "") {
|
|
2012
|
+
return { ok: false, error: repositoryResolutionFailed };
|
|
2013
|
+
}
|
|
2014
|
+
const repositoryUrl = decoded.url.endsWith("/") ? decoded.url.slice(0, -1) : decoded.url;
|
|
2015
|
+
const pullRequest = parsePullRequestUrl(`${repositoryUrl}/pull/${number}`);
|
|
2016
|
+
return pullRequest.ok ? pullRequest : { ok: false, error: repositoryResolutionFailed };
|
|
2017
|
+
}
|
|
2018
|
+
async function resolvePullRequestInput(input, options) {
|
|
2019
|
+
const direct = parsePullRequestUrl(input);
|
|
2020
|
+
if (direct.ok)
|
|
2021
|
+
return direct;
|
|
2022
|
+
if (input.trim() !== input || !/^\d+$/.test(input))
|
|
2023
|
+
return invalidPullRequestInput;
|
|
2024
|
+
const number = Number(input);
|
|
2025
|
+
if (!Number.isSafeInteger(number) || number <= 0)
|
|
2026
|
+
return invalidPullRequestInput;
|
|
2027
|
+
let stdout;
|
|
2028
|
+
try {
|
|
2029
|
+
const result = await (options.runner ?? execFileRunner)("gh", ["repo", "view", "--json", "url"], {
|
|
2030
|
+
cwd: options.directory,
|
|
2031
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2032
|
+
});
|
|
2033
|
+
stdout = result.stdout;
|
|
2034
|
+
} catch (cause) {
|
|
2035
|
+
if (isCancellation2(cause, options.signal))
|
|
2036
|
+
return repositoryResolutionCancelled;
|
|
2037
|
+
return { ok: false, error: { ...repositoryResolutionFailed, cause } };
|
|
2038
|
+
}
|
|
2039
|
+
return parseRepositoryPullRequest(stdout, number);
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
// src/state.ts
|
|
2043
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
2044
|
+
import { createHash, randomUUID } from "crypto";
|
|
2045
|
+
import { mkdir, readFile, rename, rm, writeFile } from "fs/promises";
|
|
2046
|
+
import { homedir } from "os";
|
|
2047
|
+
import { join } from "path";
|
|
2048
|
+
var maximumPullRequestsPerSession = 20;
|
|
2049
|
+
var invalidStateFile = {
|
|
2050
|
+
ok: false,
|
|
2051
|
+
error: {
|
|
2052
|
+
tag: "InvalidStateFile",
|
|
2053
|
+
message: "The session pull request state file is invalid"
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
var lockStaleMilliseconds = 1e4;
|
|
2057
|
+
var lockUpdateMilliseconds = 2000;
|
|
2058
|
+
function stateUnavailable(operation, message, cause) {
|
|
2059
|
+
return { tag: "StateUnavailable", operation, message, cause };
|
|
2060
|
+
}
|
|
2061
|
+
function isRecord2(value) {
|
|
2062
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2063
|
+
}
|
|
2064
|
+
function hasExactKeys(value, keys) {
|
|
2065
|
+
const actual = Object.keys(value);
|
|
2066
|
+
return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2067
|
+
}
|
|
2068
|
+
function parseState(input) {
|
|
2069
|
+
if (!isRecord2(input) || !hasExactKeys(input, ["version", "pullRequests"]))
|
|
2070
|
+
return invalidStateFile;
|
|
2071
|
+
if (input.version !== 1 || !Array.isArray(input.pullRequests))
|
|
2072
|
+
return invalidStateFile;
|
|
2073
|
+
if (input.pullRequests.length > maximumPullRequestsPerSession)
|
|
2074
|
+
return invalidStateFile;
|
|
2075
|
+
const attachments = [];
|
|
2076
|
+
const seen = new Set;
|
|
2077
|
+
for (const item of input.pullRequests) {
|
|
2078
|
+
if (!isRecord2(item) || !hasExactKeys(item, ["url", "attachedAt"]))
|
|
2079
|
+
return invalidStateFile;
|
|
2080
|
+
if (typeof item.url !== "string" || typeof item.attachedAt !== "string")
|
|
2081
|
+
return invalidStateFile;
|
|
2082
|
+
const parsed = parsePullRequestUrl(item.url);
|
|
2083
|
+
if (!parsed.ok || parsed.value.url !== item.url || seen.has(item.url))
|
|
2084
|
+
return invalidStateFile;
|
|
2085
|
+
const attachedAt = new Date(item.attachedAt);
|
|
2086
|
+
if (Number.isNaN(attachedAt.valueOf()) || attachedAt.toISOString() !== item.attachedAt)
|
|
2087
|
+
return invalidStateFile;
|
|
2088
|
+
seen.add(item.url);
|
|
2089
|
+
attachments.push({ pullRequest: parsed.value, attachedAt: item.attachedAt });
|
|
2090
|
+
}
|
|
2091
|
+
return { ok: true, value: attachments };
|
|
2092
|
+
}
|
|
2093
|
+
function isMissingFile(cause) {
|
|
2094
|
+
return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
2095
|
+
}
|
|
2096
|
+
function fileName(sessionID) {
|
|
2097
|
+
return `${createHash("sha256").update(sessionID).digest("hex")}.json`;
|
|
2098
|
+
}
|
|
2099
|
+
function defaultStateDirectory(environment = process.env, home = homedir()) {
|
|
2100
|
+
const dataHome = environment.XDG_DATA_HOME || join(home, ".local", "share");
|
|
2101
|
+
return join(dataHome, "opencode", "opencode-pr-tracker");
|
|
2102
|
+
}
|
|
2103
|
+
function createStateStore(options = {}) {
|
|
2104
|
+
const directory = options.directory ?? defaultStateDirectory();
|
|
2105
|
+
const now = options.now ?? (() => new Date);
|
|
2106
|
+
async function acquireLock(sessionID) {
|
|
2107
|
+
const stateFile = join(directory, fileName(sessionID));
|
|
2108
|
+
let compromised;
|
|
2109
|
+
try {
|
|
2110
|
+
await mkdir(directory, { recursive: true });
|
|
2111
|
+
const release = await import_proper_lockfile.lock(stateFile, {
|
|
2112
|
+
realpath: false,
|
|
2113
|
+
stale: lockStaleMilliseconds,
|
|
2114
|
+
update: lockUpdateMilliseconds,
|
|
2115
|
+
retries: { retries: 50, factor: 1, minTimeout: 10, maxTimeout: 100 },
|
|
2116
|
+
onCompromised: (error) => {
|
|
2117
|
+
compromised = error;
|
|
2118
|
+
}
|
|
2119
|
+
});
|
|
2120
|
+
return { ok: true, value: { release, compromised: () => compromised } };
|
|
2121
|
+
} catch (cause) {
|
|
2122
|
+
return {
|
|
2123
|
+
ok: false,
|
|
2124
|
+
error: stateUnavailable("write", "Unable to lock the session pull request state", cause)
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
async function withLock(sessionID, operation) {
|
|
2129
|
+
const lock = await acquireLock(sessionID);
|
|
2130
|
+
if (!lock.ok)
|
|
2131
|
+
return lock;
|
|
2132
|
+
let result;
|
|
2133
|
+
try {
|
|
2134
|
+
result = await operation();
|
|
2135
|
+
} catch (cause) {
|
|
2136
|
+
await lock.value.release().catch(() => {
|
|
2137
|
+
return;
|
|
2138
|
+
});
|
|
2139
|
+
throw cause;
|
|
2140
|
+
}
|
|
2141
|
+
try {
|
|
2142
|
+
await lock.value.release();
|
|
2143
|
+
} catch (cause) {
|
|
2144
|
+
return {
|
|
2145
|
+
ok: false,
|
|
2146
|
+
error: stateUnavailable("write", "Unable to unlock the session pull request state", cause)
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
const compromise = lock.value.compromised();
|
|
2150
|
+
if (compromise !== undefined) {
|
|
2151
|
+
return {
|
|
2152
|
+
ok: false,
|
|
2153
|
+
error: stateUnavailable("write", "The session pull request state lock was compromised", compromise)
|
|
2154
|
+
};
|
|
2155
|
+
}
|
|
2156
|
+
return result;
|
|
2157
|
+
}
|
|
2158
|
+
async function readExisting(sessionID) {
|
|
2159
|
+
const path = join(directory, fileName(sessionID));
|
|
2160
|
+
let content;
|
|
2161
|
+
try {
|
|
2162
|
+
content = await readFile(path, "utf8");
|
|
2163
|
+
} catch (cause) {
|
|
2164
|
+
if (isMissingFile(cause))
|
|
2165
|
+
return { ok: true, value: undefined };
|
|
2166
|
+
return {
|
|
2167
|
+
ok: false,
|
|
2168
|
+
error: stateUnavailable("read", "Unable to read the session pull request state", cause)
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
let decoded;
|
|
2172
|
+
try {
|
|
2173
|
+
decoded = JSON.parse(content);
|
|
2174
|
+
} catch {
|
|
2175
|
+
return invalidStateFile;
|
|
2176
|
+
}
|
|
2177
|
+
return parseState(decoded);
|
|
2178
|
+
}
|
|
2179
|
+
async function read(sessionID) {
|
|
2180
|
+
const result = await readExisting(sessionID);
|
|
2181
|
+
if (!result.ok)
|
|
2182
|
+
return result;
|
|
2183
|
+
return { ok: true, value: result.value ?? [] };
|
|
2184
|
+
}
|
|
2185
|
+
async function write(sessionID, attachments) {
|
|
2186
|
+
const destination = join(directory, fileName(sessionID));
|
|
2187
|
+
const temporary = `${destination}.${process.pid}.${randomUUID()}.tmp`;
|
|
2188
|
+
const state = {
|
|
2189
|
+
version: 1,
|
|
2190
|
+
pullRequests: attachments.map((attachment) => ({
|
|
2191
|
+
url: attachment.pullRequest.url,
|
|
2192
|
+
attachedAt: attachment.attachedAt
|
|
2193
|
+
}))
|
|
2194
|
+
};
|
|
2195
|
+
try {
|
|
2196
|
+
await mkdir(directory, { recursive: true });
|
|
2197
|
+
await writeFile(temporary, `${JSON.stringify(state, null, 2)}
|
|
2198
|
+
`, { mode: 384 });
|
|
2199
|
+
await rename(temporary, destination);
|
|
2200
|
+
return { ok: true, value: undefined };
|
|
2201
|
+
} catch (cause) {
|
|
2202
|
+
await rm(temporary, { force: true }).catch(() => {
|
|
2203
|
+
return;
|
|
2204
|
+
});
|
|
2205
|
+
return {
|
|
2206
|
+
ok: false,
|
|
2207
|
+
error: stateUnavailable("write", "Unable to write the session pull request state", cause)
|
|
2208
|
+
};
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
return {
|
|
2212
|
+
list: read,
|
|
2213
|
+
async attach(sessionID, pullRequest) {
|
|
2214
|
+
return withLock(sessionID, async () => {
|
|
2215
|
+
const current = await read(sessionID);
|
|
2216
|
+
if (!current.ok)
|
|
2217
|
+
return current;
|
|
2218
|
+
if (current.value.some((attachment) => attachment.pullRequest.url === pullRequest.url)) {
|
|
2219
|
+
return { ok: true, value: "already_attached" };
|
|
2220
|
+
}
|
|
2221
|
+
if (current.value.length >= maximumPullRequestsPerSession) {
|
|
2222
|
+
return {
|
|
2223
|
+
ok: false,
|
|
2224
|
+
error: {
|
|
2225
|
+
tag: "AttachmentLimitReached",
|
|
2226
|
+
limit: maximumPullRequestsPerSession,
|
|
2227
|
+
message: "A session can track at most 20 pull requests"
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
}
|
|
2231
|
+
const written = await write(sessionID, [...current.value, { pullRequest, attachedAt: now().toISOString() }]);
|
|
2232
|
+
if (!written.ok)
|
|
2233
|
+
return written;
|
|
2234
|
+
return { ok: true, value: "added" };
|
|
2235
|
+
});
|
|
2236
|
+
},
|
|
2237
|
+
async detach(sessionID, pullRequest) {
|
|
2238
|
+
return withLock(sessionID, async () => {
|
|
2239
|
+
const current = await read(sessionID);
|
|
2240
|
+
if (!current.ok)
|
|
2241
|
+
return current;
|
|
2242
|
+
const next = current.value.filter((attachment) => attachment.pullRequest.url !== pullRequest.url);
|
|
2243
|
+
if (next.length === current.value.length)
|
|
2244
|
+
return { ok: true, value: "absent" };
|
|
2245
|
+
const written = await write(sessionID, next);
|
|
2246
|
+
if (!written.ok)
|
|
2247
|
+
return written;
|
|
2248
|
+
return { ok: true, value: "removed" };
|
|
2249
|
+
});
|
|
2250
|
+
},
|
|
2251
|
+
async detachByNumber(sessionID, number) {
|
|
2252
|
+
return withLock(sessionID, async () => {
|
|
2253
|
+
const current = await read(sessionID);
|
|
2254
|
+
if (!current.ok)
|
|
2255
|
+
return current;
|
|
2256
|
+
const matches = current.value.filter((attachment) => attachment.pullRequest.number === number);
|
|
2257
|
+
if (matches.length === 0)
|
|
2258
|
+
return { ok: true, value: { tag: "absent" } };
|
|
2259
|
+
if (matches.length > 1) {
|
|
2260
|
+
return {
|
|
2261
|
+
ok: true,
|
|
2262
|
+
value: { tag: "ambiguous", pullRequests: matches.map((attachment) => attachment.pullRequest) }
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
const match = matches[0];
|
|
2266
|
+
if (match === undefined)
|
|
2267
|
+
return { ok: true, value: { tag: "absent" } };
|
|
2268
|
+
const next = current.value.filter((attachment) => attachment.pullRequest.url !== match.pullRequest.url);
|
|
2269
|
+
const written = await write(sessionID, next);
|
|
2270
|
+
if (!written.ok)
|
|
2271
|
+
return written;
|
|
2272
|
+
return { ok: true, value: { tag: "removed", pullRequest: match.pullRequest } };
|
|
2273
|
+
});
|
|
2274
|
+
},
|
|
2275
|
+
async removeSession(sessionID) {
|
|
2276
|
+
return withLock(sessionID, async () => {
|
|
2277
|
+
const current = await readExisting(sessionID);
|
|
2278
|
+
if (!current.ok)
|
|
2279
|
+
return current;
|
|
2280
|
+
if (current.value === undefined)
|
|
2281
|
+
return { ok: true, value: "absent" };
|
|
2282
|
+
try {
|
|
2283
|
+
await rm(join(directory, fileName(sessionID)), { force: true });
|
|
2284
|
+
return { ok: true, value: "removed" };
|
|
2285
|
+
} catch (cause) {
|
|
2286
|
+
return {
|
|
2287
|
+
ok: false,
|
|
2288
|
+
error: stateUnavailable("write", "Unable to remove the session pull request state", cause)
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// src/tui.tsx
|
|
2297
|
+
var pollIntervalMilliseconds = 60000;
|
|
2298
|
+
var defaultScheduler = {
|
|
2299
|
+
setInterval: (task, delay) => globalThis.setInterval(task, delay),
|
|
2300
|
+
clearInterval: (handle) => globalThis.clearInterval(handle)
|
|
2301
|
+
};
|
|
2302
|
+
function attachPullRequest(store, sessionID, input) {
|
|
2303
|
+
const pullRequest = parsePullRequestUrl(input);
|
|
2304
|
+
if (!pullRequest.ok)
|
|
2305
|
+
return Promise.resolve(pullRequest);
|
|
2306
|
+
return store.attach(sessionID, pullRequest.value);
|
|
2307
|
+
}
|
|
2308
|
+
function startSessionPolling(input) {
|
|
2309
|
+
const scheduler = input.scheduler ?? defaultScheduler;
|
|
2310
|
+
const statuses = new Map;
|
|
2311
|
+
const controller = new AbortController;
|
|
2312
|
+
let timer;
|
|
2313
|
+
let timerRegistered = false;
|
|
2314
|
+
let stopped = false;
|
|
2315
|
+
let inFlight;
|
|
2316
|
+
let refreshQueued = false;
|
|
2317
|
+
function project(attachments) {
|
|
2318
|
+
return attachments.map((attachment) => ({
|
|
2319
|
+
attachment,
|
|
2320
|
+
status: statuses.get(attachment.pullRequest.url) ?? {
|
|
2321
|
+
tag: "Unavailable"
|
|
2322
|
+
}
|
|
2323
|
+
}));
|
|
2324
|
+
}
|
|
2325
|
+
async function poll() {
|
|
2326
|
+
const attachments = await input.store.list(input.sessionID);
|
|
2327
|
+
if (stopped)
|
|
2328
|
+
return;
|
|
2329
|
+
if (!attachments.ok) {
|
|
2330
|
+
input.publish([]);
|
|
2331
|
+
input.onStateFailure(attachments.error);
|
|
2332
|
+
return;
|
|
2333
|
+
}
|
|
2334
|
+
const attachedUrls = new Set(attachments.value.map((attachment) => attachment.pullRequest.url));
|
|
2335
|
+
for (const url of statuses.keys()) {
|
|
2336
|
+
if (!attachedUrls.has(url))
|
|
2337
|
+
statuses.delete(url);
|
|
2338
|
+
}
|
|
2339
|
+
input.publish(project(attachments.value));
|
|
2340
|
+
const refreshable = attachments.value.filter((attachment) => {
|
|
2341
|
+
const previous = statuses.get(attachment.pullRequest.url);
|
|
2342
|
+
return previous?.tag !== "Available" || previous.state.tag !== "Merged";
|
|
2343
|
+
});
|
|
2344
|
+
const batch = await input.github.get(refreshable.map((attachment) => attachment.pullRequest), {
|
|
2345
|
+
signal: controller.signal
|
|
2346
|
+
});
|
|
2347
|
+
if (stopped)
|
|
2348
|
+
return;
|
|
2349
|
+
let batchDiagnostic;
|
|
2350
|
+
if (!batch.ok) {
|
|
2351
|
+
if (batch.error.tag === "GitHubCancelled")
|
|
2352
|
+
return;
|
|
2353
|
+
batchDiagnostic = batch.error.tag === "GitHubBatchLimitExceeded" ? "GitHubUnavailable" : batch.error.tag;
|
|
2354
|
+
}
|
|
2355
|
+
for (const [index, attachment] of refreshable.entries()) {
|
|
2356
|
+
const previous = statuses.get(attachment.pullRequest.url);
|
|
2357
|
+
const result = batch.ok ? batch.value[index] : undefined;
|
|
2358
|
+
if (result?.ok) {
|
|
2359
|
+
statuses.set(attachment.pullRequest.url, result.value);
|
|
2360
|
+
continue;
|
|
2361
|
+
}
|
|
2362
|
+
const diagnostic = result === undefined ? batchDiagnostic ?? "GitHubUnavailable" : result.error.tag;
|
|
2363
|
+
statuses.set(attachment.pullRequest.url, previous?.tag === "Available" ? {
|
|
2364
|
+
...previous,
|
|
2365
|
+
stale: true,
|
|
2366
|
+
diagnostic
|
|
2367
|
+
} : {
|
|
2368
|
+
tag: "Unavailable",
|
|
2369
|
+
diagnostic
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
if (!stopped)
|
|
2373
|
+
input.publish(project(attachments.value));
|
|
2374
|
+
}
|
|
2375
|
+
function refresh() {
|
|
2376
|
+
if (stopped)
|
|
2377
|
+
return Promise.resolve();
|
|
2378
|
+
if (inFlight) {
|
|
2379
|
+
refreshQueued = true;
|
|
2380
|
+
return inFlight;
|
|
2381
|
+
}
|
|
2382
|
+
const wrapped = poll().finally(() => {
|
|
2383
|
+
inFlight = undefined;
|
|
2384
|
+
if (refreshQueued && !stopped) {
|
|
2385
|
+
refreshQueued = false;
|
|
2386
|
+
return refresh();
|
|
2387
|
+
}
|
|
2388
|
+
return;
|
|
2389
|
+
});
|
|
2390
|
+
inFlight = wrapped;
|
|
2391
|
+
return wrapped;
|
|
2392
|
+
}
|
|
2393
|
+
return {
|
|
2394
|
+
start() {
|
|
2395
|
+
if (stopped)
|
|
2396
|
+
return Promise.resolve();
|
|
2397
|
+
if (!timerRegistered) {
|
|
2398
|
+
timer = scheduler.setInterval(() => {
|
|
2399
|
+
refresh().catch(input.onError);
|
|
2400
|
+
}, pollIntervalMilliseconds);
|
|
2401
|
+
timerRegistered = true;
|
|
2402
|
+
}
|
|
2403
|
+
return refresh();
|
|
2404
|
+
},
|
|
2405
|
+
refresh,
|
|
2406
|
+
stop() {
|
|
2407
|
+
if (stopped)
|
|
2408
|
+
return;
|
|
2409
|
+
stopped = true;
|
|
2410
|
+
controller.abort();
|
|
2411
|
+
if (timerRegistered)
|
|
2412
|
+
scheduler.clearInterval(timer);
|
|
2413
|
+
}
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
async function openPullRequest(pullRequest, options = {}) {
|
|
2417
|
+
const platform = options.platform ?? process.platform;
|
|
2418
|
+
const executable = platform === "darwin" ? "open" : platform === "linux" ? "xdg-open" : undefined;
|
|
2419
|
+
if (executable === undefined) {
|
|
2420
|
+
return {
|
|
2421
|
+
ok: false,
|
|
2422
|
+
error: {
|
|
2423
|
+
tag: "UnsupportedPlatform",
|
|
2424
|
+
message: `Opening pull requests is unsupported on ${platform}`,
|
|
2425
|
+
platform
|
|
2426
|
+
}
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
try {
|
|
2430
|
+
await (options.runner ?? execFileRunner)(executable, [pullRequest.url], options.signal ? {
|
|
2431
|
+
signal: options.signal
|
|
2432
|
+
} : {});
|
|
2433
|
+
return {
|
|
2434
|
+
ok: true,
|
|
2435
|
+
value: undefined
|
|
2436
|
+
};
|
|
2437
|
+
} catch (cause) {
|
|
2438
|
+
return {
|
|
2439
|
+
ok: false,
|
|
2440
|
+
error: {
|
|
2441
|
+
tag: "OpenPullRequestFailed",
|
|
2442
|
+
message: "Unable to open the pull request",
|
|
2443
|
+
cause
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
function createRefreshBus() {
|
|
2449
|
+
const listeners = new Map;
|
|
2450
|
+
return {
|
|
2451
|
+
emit(sessionID) {
|
|
2452
|
+
for (const listener of listeners.get(sessionID) ?? [])
|
|
2453
|
+
listener();
|
|
2454
|
+
},
|
|
2455
|
+
subscribe(sessionID, listener) {
|
|
2456
|
+
const sessionListeners = listeners.get(sessionID) ?? new Set;
|
|
2457
|
+
sessionListeners.add(listener);
|
|
2458
|
+
listeners.set(sessionID, sessionListeners);
|
|
2459
|
+
return () => {
|
|
2460
|
+
sessionListeners.delete(listener);
|
|
2461
|
+
if (sessionListeners.size === 0)
|
|
2462
|
+
listeners.delete(sessionID);
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
function currentSessionID(api) {
|
|
2468
|
+
const route = api.route.current;
|
|
2469
|
+
if (route.name !== "session" || !("params" in route))
|
|
2470
|
+
return;
|
|
2471
|
+
return typeof route.params?.sessionID === "string" ? route.params.sessionID : undefined;
|
|
2472
|
+
}
|
|
2473
|
+
function promptForPullRequest(api, options) {
|
|
2474
|
+
return new Promise((resolve) => {
|
|
2475
|
+
const controller = new AbortController;
|
|
2476
|
+
const signal = AbortSignal.any([options.signal, controller.signal]);
|
|
2477
|
+
let finished = false;
|
|
2478
|
+
const finish = (value) => {
|
|
2479
|
+
if (finished)
|
|
2480
|
+
return;
|
|
2481
|
+
finished = true;
|
|
2482
|
+
controller.abort();
|
|
2483
|
+
api.ui.dialog.clear();
|
|
2484
|
+
resolve(value);
|
|
2485
|
+
};
|
|
2486
|
+
api.ui.dialog.setSize("medium");
|
|
2487
|
+
api.ui.dialog.replace(() => {
|
|
2488
|
+
const [error, setError] = createSignal();
|
|
2489
|
+
const [busy, setBusy] = createSignal(false);
|
|
2490
|
+
const DialogPrompt = api.ui.DialogPrompt;
|
|
2491
|
+
return _$createComponent(DialogPrompt, {
|
|
2492
|
+
title: "Attach pull request",
|
|
2493
|
+
placeholder: "https://github.com/owner/repository/pull/123 or 123",
|
|
2494
|
+
description: () => error() ? (() => {
|
|
2495
|
+
var _el$ = _$createElement("text");
|
|
2496
|
+
_$insert(_el$, error);
|
|
2497
|
+
_$effect((_$p) => _$setProp(_el$, "fg", api.theme.current.error, _$p));
|
|
2498
|
+
return _el$;
|
|
2499
|
+
})() : null,
|
|
2500
|
+
get busy() {
|
|
2501
|
+
return busy();
|
|
2502
|
+
},
|
|
2503
|
+
busyText: "Resolving repository",
|
|
2504
|
+
onConfirm: (value) => {
|
|
2505
|
+
if (busy())
|
|
2506
|
+
return;
|
|
2507
|
+
setBusy(true);
|
|
2508
|
+
resolvePullRequestInput(value, {
|
|
2509
|
+
directory: options.directory,
|
|
2510
|
+
...options.runner ? {
|
|
2511
|
+
runner: options.runner
|
|
2512
|
+
} : {},
|
|
2513
|
+
signal
|
|
2514
|
+
}).then((result) => {
|
|
2515
|
+
if (finished)
|
|
2516
|
+
return;
|
|
2517
|
+
setBusy(false);
|
|
2518
|
+
if (result.ok) {
|
|
2519
|
+
finish(result.value);
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
if (result.error.tag === "RepositoryResolutionCancelled") {
|
|
2523
|
+
finish(undefined);
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2526
|
+
setError(result.error.message);
|
|
2527
|
+
});
|
|
2528
|
+
},
|
|
2529
|
+
onCancel: () => finish(undefined)
|
|
2530
|
+
});
|
|
2531
|
+
}, () => {
|
|
2532
|
+
if (finished)
|
|
2533
|
+
return;
|
|
2534
|
+
finished = true;
|
|
2535
|
+
controller.abort();
|
|
2536
|
+
resolve(undefined);
|
|
2537
|
+
});
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
function selectPullRequest(api, title, attachments) {
|
|
2541
|
+
return new Promise((resolve) => {
|
|
2542
|
+
let finished = false;
|
|
2543
|
+
const finish = (value) => {
|
|
2544
|
+
if (finished)
|
|
2545
|
+
return;
|
|
2546
|
+
finished = true;
|
|
2547
|
+
api.ui.dialog.clear();
|
|
2548
|
+
resolve(value);
|
|
2549
|
+
};
|
|
2550
|
+
api.ui.dialog.setSize("medium");
|
|
2551
|
+
api.ui.dialog.replace(() => {
|
|
2552
|
+
const DialogSelect = api.ui.DialogSelect;
|
|
2553
|
+
return _$createComponent(DialogSelect, {
|
|
2554
|
+
title,
|
|
2555
|
+
get options() {
|
|
2556
|
+
return attachments.map((attachment) => ({
|
|
2557
|
+
title: formatPullRequestRef(attachment.pullRequest),
|
|
2558
|
+
value: attachment.pullRequest,
|
|
2559
|
+
description: attachment.pullRequest.url
|
|
2560
|
+
}));
|
|
2561
|
+
},
|
|
2562
|
+
onSelect: (option) => finish(option.value)
|
|
2563
|
+
});
|
|
2564
|
+
}, () => {
|
|
2565
|
+
if (!finished)
|
|
2566
|
+
resolve(undefined);
|
|
2567
|
+
});
|
|
2568
|
+
});
|
|
2569
|
+
}
|
|
2570
|
+
function showStateFailure(api, failure) {
|
|
2571
|
+
api.ui.toast({
|
|
2572
|
+
variant: "error",
|
|
2573
|
+
title: "Pull request tracker",
|
|
2574
|
+
message: failure.message
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
function toneColor(theme, tone) {
|
|
2578
|
+
const colors = {
|
|
2579
|
+
green: theme.success,
|
|
2580
|
+
yellow: theme.warning,
|
|
2581
|
+
red: theme.error,
|
|
2582
|
+
purple: theme.secondary,
|
|
2583
|
+
gray: theme.textMuted
|
|
2584
|
+
};
|
|
2585
|
+
return colors[tone];
|
|
2586
|
+
}
|
|
2587
|
+
function PullRequestSidebar(props) {
|
|
2588
|
+
const [items, setItems] = createSignal([]);
|
|
2589
|
+
const [failure, setFailure] = createSignal();
|
|
2590
|
+
const polling = startSessionPolling({
|
|
2591
|
+
sessionID: props.sessionID,
|
|
2592
|
+
store: props.dependencies.store,
|
|
2593
|
+
github: props.dependencies.github,
|
|
2594
|
+
publish: (value) => {
|
|
2595
|
+
setFailure(undefined);
|
|
2596
|
+
setItems(value);
|
|
2597
|
+
},
|
|
2598
|
+
onStateFailure: (error) => setFailure(error.message),
|
|
2599
|
+
onError: () => setFailure("Unable to refresh pull request status")
|
|
2600
|
+
});
|
|
2601
|
+
polling.start().catch(() => setFailure("Unable to refresh pull request status"));
|
|
2602
|
+
const unsubscribe = props.refreshBus.subscribe(props.sessionID, () => {
|
|
2603
|
+
polling.refresh().catch(() => setFailure("Unable to refresh pull request status"));
|
|
2604
|
+
});
|
|
2605
|
+
const onAbort = () => polling.stop();
|
|
2606
|
+
props.api.lifecycle.signal.addEventListener("abort", onAbort, {
|
|
2607
|
+
once: true
|
|
2608
|
+
});
|
|
2609
|
+
onCleanup(() => {
|
|
2610
|
+
unsubscribe();
|
|
2611
|
+
polling.stop();
|
|
2612
|
+
props.api.lifecycle.signal.removeEventListener("abort", onAbort);
|
|
2613
|
+
});
|
|
2614
|
+
return (() => {
|
|
2615
|
+
var _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$4 = _$createElement("b");
|
|
2616
|
+
_$insertNode(_el$2, _el$3);
|
|
2617
|
+
_$setProp(_el$2, "flexDirection", "column");
|
|
2618
|
+
_$setProp(_el$2, "gap", 1);
|
|
2619
|
+
_$insertNode(_el$3, _el$4);
|
|
2620
|
+
_$insertNode(_el$4, _$createTextNode(`Pull requests`));
|
|
2621
|
+
_$insert(_el$2, (() => {
|
|
2622
|
+
var _c$ = _$memo(() => !!failure());
|
|
2623
|
+
return () => _c$() ? (() => {
|
|
2624
|
+
var _el$6 = _$createElement("text");
|
|
2625
|
+
_$insert(_el$6, failure);
|
|
2626
|
+
_$effect((_$p) => _$setProp(_el$6, "fg", props.api.theme.current.error, _$p));
|
|
2627
|
+
return _el$6;
|
|
2628
|
+
})() : null;
|
|
2629
|
+
})(), null);
|
|
2630
|
+
_$insert(_el$2, (() => {
|
|
2631
|
+
var _c$2 = _$memo(() => !!(!failure() && items().length === 0));
|
|
2632
|
+
return () => _c$2() ? (() => {
|
|
2633
|
+
var _el$7 = _$createElement("text");
|
|
2634
|
+
_$insertNode(_el$7, _$createTextNode(`No pull requests attached`));
|
|
2635
|
+
_$effect((_$p) => _$setProp(_el$7, "fg", props.api.theme.current.textMuted, _$p));
|
|
2636
|
+
return _el$7;
|
|
2637
|
+
})() : null;
|
|
2638
|
+
})(), null);
|
|
2639
|
+
_$insert(_el$2, () => items().map((item) => {
|
|
2640
|
+
const appearance = statusAppearance(item.status);
|
|
2641
|
+
const attributes = appearance.strikethrough ? TextAttributes.STRIKETHROUGH : TextAttributes.NONE;
|
|
2642
|
+
const title = item.status.tag === "Available" ? item.status.title : "Title unavailable";
|
|
2643
|
+
return (() => {
|
|
2644
|
+
var _el$9 = _$createElement("box"), _el$0 = _$createElement("text"), _el$1 = _$createElement("b"), _el$10 = _$createTextNode(` `), _el$11 = _$createElement("text");
|
|
2645
|
+
_$insertNode(_el$9, _el$0);
|
|
2646
|
+
_$insertNode(_el$9, _el$11);
|
|
2647
|
+
_$setProp(_el$9, "flexDirection", "column");
|
|
2648
|
+
_$setProp(_el$9, "onMouseUp", () => {
|
|
2649
|
+
openPullRequest(item.attachment.pullRequest, {
|
|
2650
|
+
...props.dependencies.runner ? {
|
|
2651
|
+
runner: props.dependencies.runner
|
|
2652
|
+
} : {},
|
|
2653
|
+
signal: props.api.lifecycle.signal
|
|
2654
|
+
}).then((result) => {
|
|
2655
|
+
if (!result.ok) {
|
|
2656
|
+
props.api.ui.toast({
|
|
2657
|
+
variant: "error",
|
|
2658
|
+
title: "Pull request tracker",
|
|
2659
|
+
message: result.error.message
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2662
|
+
}).catch(() => {
|
|
2663
|
+
props.api.ui.toast({
|
|
2664
|
+
variant: "error",
|
|
2665
|
+
title: "Pull request tracker",
|
|
2666
|
+
message: "Unable to open the pull request"
|
|
2667
|
+
});
|
|
2668
|
+
});
|
|
2669
|
+
});
|
|
2670
|
+
_$insertNode(_el$0, _el$1);
|
|
2671
|
+
_$insertNode(_el$0, _el$10);
|
|
2672
|
+
_$setProp(_el$0, "attributes", attributes);
|
|
2673
|
+
_$insert(_el$1, () => formatPullRequestRef(item.attachment.pullRequest));
|
|
2674
|
+
_$insert(_el$0, () => appearance.label, null);
|
|
2675
|
+
_$setProp(_el$11, "attributes", attributes);
|
|
2676
|
+
_$insert(_el$11, title);
|
|
2677
|
+
_$effect((_p$) => {
|
|
2678
|
+
var _v$ = toneColor(props.api.theme.current, appearance.tone), _v$2 = props.api.theme.current.textMuted;
|
|
2679
|
+
_v$ !== _p$.e && (_p$.e = _$setProp(_el$0, "fg", _v$, _p$.e));
|
|
2680
|
+
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$11, "fg", _v$2, _p$.t));
|
|
2681
|
+
return _p$;
|
|
2682
|
+
}, {
|
|
2683
|
+
e: undefined,
|
|
2684
|
+
t: undefined
|
|
2685
|
+
});
|
|
2686
|
+
return _el$9;
|
|
2687
|
+
})();
|
|
2688
|
+
}), null);
|
|
2689
|
+
_$effect((_$p) => _$setProp(_el$3, "fg", props.api.theme.current.text, _$p));
|
|
2690
|
+
return _el$2;
|
|
2691
|
+
})();
|
|
2692
|
+
}
|
|
2693
|
+
function registerTui(api, dependencies) {
|
|
2694
|
+
const refreshBus = createRefreshBus();
|
|
2695
|
+
api.event.on("session.updated", (event) => refreshBus.emit(event.properties.sessionID));
|
|
2696
|
+
api.event.on("message.updated", (event) => refreshBus.emit(event.properties.sessionID));
|
|
2697
|
+
api.event.on("message.part.updated", (event) => refreshBus.emit(event.properties.sessionID));
|
|
2698
|
+
const disposeCommands = api.keymap.registerLayer({
|
|
2699
|
+
commands: [{
|
|
2700
|
+
name: "pr.attach",
|
|
2701
|
+
title: "Attach pull request",
|
|
2702
|
+
category: "Plugin",
|
|
2703
|
+
namespace: "palette",
|
|
2704
|
+
slashName: "pr-attach",
|
|
2705
|
+
async run() {
|
|
2706
|
+
const sessionID = currentSessionID(api);
|
|
2707
|
+
if (sessionID === undefined) {
|
|
2708
|
+
api.ui.toast({
|
|
2709
|
+
variant: "warning",
|
|
2710
|
+
title: "Pull request tracker",
|
|
2711
|
+
message: "Open a session first"
|
|
2712
|
+
});
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
const pullRequest = await promptForPullRequest(api, {
|
|
2716
|
+
directory: api.state.path.directory,
|
|
2717
|
+
...dependencies.runner ? {
|
|
2718
|
+
runner: dependencies.runner
|
|
2719
|
+
} : {},
|
|
2720
|
+
signal: api.lifecycle.signal
|
|
2721
|
+
});
|
|
2722
|
+
if (pullRequest === undefined)
|
|
2723
|
+
return;
|
|
2724
|
+
const result = await dependencies.store.attach(sessionID, pullRequest);
|
|
2725
|
+
if (!result.ok) {
|
|
2726
|
+
showStateFailure(api, result.error);
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
const message = result.value === "added" ? `Attached ${formatPullRequestRef(pullRequest)}` : `${formatPullRequestRef(pullRequest)} is already attached`;
|
|
2730
|
+
api.ui.toast({
|
|
2731
|
+
variant: "success",
|
|
2732
|
+
title: "Pull request tracker",
|
|
2733
|
+
message
|
|
2734
|
+
});
|
|
2735
|
+
refreshBus.emit(sessionID);
|
|
2736
|
+
}
|
|
2737
|
+
}, {
|
|
2738
|
+
name: "pr.open",
|
|
2739
|
+
title: "Open pull request",
|
|
2740
|
+
category: "Plugin",
|
|
2741
|
+
namespace: "palette",
|
|
2742
|
+
slashName: "pr-open",
|
|
2743
|
+
async run() {
|
|
2744
|
+
const sessionID = currentSessionID(api);
|
|
2745
|
+
if (sessionID === undefined) {
|
|
2746
|
+
api.ui.toast({
|
|
2747
|
+
variant: "warning",
|
|
2748
|
+
title: "Pull request tracker",
|
|
2749
|
+
message: "Open a session first"
|
|
2750
|
+
});
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
const attachments = await dependencies.store.list(sessionID);
|
|
2754
|
+
if (!attachments.ok) {
|
|
2755
|
+
showStateFailure(api, attachments.error);
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
if (attachments.value.length === 0) {
|
|
2759
|
+
api.ui.toast({
|
|
2760
|
+
variant: "info",
|
|
2761
|
+
title: "Pull request tracker",
|
|
2762
|
+
message: "No pull requests are attached"
|
|
2763
|
+
});
|
|
2764
|
+
return;
|
|
2765
|
+
}
|
|
2766
|
+
const pullRequest = await selectPullRequest(api, "Open pull request", attachments.value);
|
|
2767
|
+
if (pullRequest === undefined)
|
|
2768
|
+
return;
|
|
2769
|
+
const result = await openPullRequest(pullRequest, {
|
|
2770
|
+
...dependencies.runner ? {
|
|
2771
|
+
runner: dependencies.runner
|
|
2772
|
+
} : {},
|
|
2773
|
+
signal: api.lifecycle.signal
|
|
2774
|
+
});
|
|
2775
|
+
if (!result.ok) {
|
|
2776
|
+
api.ui.toast({
|
|
2777
|
+
variant: "error",
|
|
2778
|
+
title: "Pull request tracker",
|
|
2779
|
+
message: result.error.message
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}, {
|
|
2784
|
+
name: "pr.detach",
|
|
2785
|
+
title: "Detach pull request",
|
|
2786
|
+
category: "Plugin",
|
|
2787
|
+
namespace: "palette",
|
|
2788
|
+
slashName: "pr-detach",
|
|
2789
|
+
async run() {
|
|
2790
|
+
const sessionID = currentSessionID(api);
|
|
2791
|
+
if (sessionID === undefined) {
|
|
2792
|
+
api.ui.toast({
|
|
2793
|
+
variant: "warning",
|
|
2794
|
+
title: "Pull request tracker",
|
|
2795
|
+
message: "Open a session first"
|
|
2796
|
+
});
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
const attachments = await dependencies.store.list(sessionID);
|
|
2800
|
+
if (!attachments.ok) {
|
|
2801
|
+
showStateFailure(api, attachments.error);
|
|
2802
|
+
return;
|
|
2803
|
+
}
|
|
2804
|
+
if (attachments.value.length === 0) {
|
|
2805
|
+
api.ui.toast({
|
|
2806
|
+
variant: "info",
|
|
2807
|
+
title: "Pull request tracker",
|
|
2808
|
+
message: "No pull requests are attached"
|
|
2809
|
+
});
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
const pullRequest = await selectPullRequest(api, "Detach pull request", attachments.value);
|
|
2813
|
+
if (pullRequest === undefined)
|
|
2814
|
+
return;
|
|
2815
|
+
const result = await dependencies.store.detach(sessionID, pullRequest);
|
|
2816
|
+
if (!result.ok) {
|
|
2817
|
+
showStateFailure(api, result.error);
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2820
|
+
const message = result.value === "removed" ? `Detached ${formatPullRequestRef(pullRequest)}` : `${formatPullRequestRef(pullRequest)} was not attached`;
|
|
2821
|
+
api.ui.toast({
|
|
2822
|
+
variant: "success",
|
|
2823
|
+
title: "Pull request tracker",
|
|
2824
|
+
message
|
|
2825
|
+
});
|
|
2826
|
+
refreshBus.emit(sessionID);
|
|
2827
|
+
}
|
|
2828
|
+
}],
|
|
2829
|
+
bindings: []
|
|
2830
|
+
});
|
|
2831
|
+
api.lifecycle.onDispose(disposeCommands);
|
|
2832
|
+
api.slots.register({
|
|
2833
|
+
order: 250,
|
|
2834
|
+
slots: {
|
|
2835
|
+
sidebar_content(_context, value) {
|
|
2836
|
+
return _$createComponent(PullRequestSidebar, {
|
|
2837
|
+
api,
|
|
2838
|
+
get sessionID() {
|
|
2839
|
+
return value.session_id;
|
|
2840
|
+
},
|
|
2841
|
+
dependencies,
|
|
2842
|
+
refreshBus
|
|
2843
|
+
});
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
});
|
|
2847
|
+
}
|
|
2848
|
+
var plugin = {
|
|
2849
|
+
id: "opencode-pr-tracker",
|
|
2850
|
+
async tui(api, options) {
|
|
2851
|
+
if (options?.enabled === false)
|
|
2852
|
+
return;
|
|
2853
|
+
registerTui(api, {
|
|
2854
|
+
store: createStateStore(),
|
|
2855
|
+
github: createGitHubClient()
|
|
2856
|
+
});
|
|
2857
|
+
}
|
|
2858
|
+
};
|
|
2859
|
+
var tui_default = plugin;
|
|
2860
|
+
export {
|
|
2861
|
+
startSessionPolling,
|
|
2862
|
+
registerTui,
|
|
2863
|
+
openPullRequest,
|
|
2864
|
+
tui_default as default,
|
|
2865
|
+
attachPullRequest
|
|
2866
|
+
};
|
|
2867
|
+
|
|
2868
|
+
//# debugId=73D7339550CD79BA64756E2164756E21
|