@spzhongwin/skill-logger-plugin 1.0.16 → 1.0.17
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/dist/index.js +3478 -221
- package/openclaw.plugin.json +50 -50
- package/package.json +34 -34
- package/src/active-skills.test.ts +32 -32
- package/src/active-skills.ts +77 -77
- package/src/config-sync.test.ts +165 -165
- package/src/config-sync.ts +544 -544
- package/src/expert-skill-layout.test.ts +196 -196
- package/src/expert-skill-layout.ts +233 -233
- package/src/hooks.test.ts +228 -228
- package/src/hooks.ts +494 -494
- package/src/http.ts +61 -61
- package/src/identity.ts +88 -88
- package/src/index.test.ts +53 -53
- package/src/index.ts +218 -218
- package/src/integration.test.ts +119 -119
- package/src/matcher.test.ts +170 -170
- package/src/matcher.ts +393 -393
- package/src/paths.test.ts +57 -57
- package/src/paths.ts +84 -84
- package/src/reporter.test.ts +139 -139
- package/src/reporter.ts +303 -303
- package/src/sample-config.json +72 -72
- package/src/semver.test.ts +33 -33
- package/src/semver.ts +65 -65
- package/src/skill-version.ts +53 -53
- package/src/types.ts +202 -202
- package/src/updater.test.ts +431 -431
- package/src/updater.ts +584 -584
- package/src/ws-client.test.ts +247 -158
- package/src/ws-client.ts +917 -805
- package/test-ws.ts +17 -17
- package/tsconfig.json +18 -18
package/dist/index.js
CHANGED
|
@@ -1,6 +1,2757 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
// node_modules/adm-zip/util/constants.js
|
|
34
|
+
var require_constants = __commonJS({
|
|
35
|
+
"node_modules/adm-zip/util/constants.js"(exports, module) {
|
|
36
|
+
module.exports = {
|
|
37
|
+
/* The local file header */
|
|
38
|
+
LOCHDR: 30,
|
|
39
|
+
// LOC header size
|
|
40
|
+
LOCSIG: 67324752,
|
|
41
|
+
// "PK\003\004"
|
|
42
|
+
LOCVER: 4,
|
|
43
|
+
// version needed to extract
|
|
44
|
+
LOCFLG: 6,
|
|
45
|
+
// general purpose bit flag
|
|
46
|
+
LOCHOW: 8,
|
|
47
|
+
// compression method
|
|
48
|
+
LOCTIM: 10,
|
|
49
|
+
// modification time (2 bytes time, 2 bytes date)
|
|
50
|
+
LOCCRC: 14,
|
|
51
|
+
// uncompressed file crc-32 value
|
|
52
|
+
LOCSIZ: 18,
|
|
53
|
+
// compressed size
|
|
54
|
+
LOCLEN: 22,
|
|
55
|
+
// uncompressed size
|
|
56
|
+
LOCNAM: 26,
|
|
57
|
+
// filename length
|
|
58
|
+
LOCEXT: 28,
|
|
59
|
+
// extra field length
|
|
60
|
+
/* The Data descriptor */
|
|
61
|
+
EXTSIG: 134695760,
|
|
62
|
+
// "PK\007\008"
|
|
63
|
+
EXTHDR: 16,
|
|
64
|
+
// EXT header size
|
|
65
|
+
EXTCRC: 4,
|
|
66
|
+
// uncompressed file crc-32 value
|
|
67
|
+
EXTSIZ: 8,
|
|
68
|
+
// compressed size
|
|
69
|
+
EXTLEN: 12,
|
|
70
|
+
// uncompressed size
|
|
71
|
+
/* The central directory file header */
|
|
72
|
+
CENHDR: 46,
|
|
73
|
+
// CEN header size
|
|
74
|
+
CENSIG: 33639248,
|
|
75
|
+
// "PK\001\002"
|
|
76
|
+
CENVEM: 4,
|
|
77
|
+
// version made by
|
|
78
|
+
CENVER: 6,
|
|
79
|
+
// version needed to extract
|
|
80
|
+
CENFLG: 8,
|
|
81
|
+
// encrypt, decrypt flags
|
|
82
|
+
CENHOW: 10,
|
|
83
|
+
// compression method
|
|
84
|
+
CENTIM: 12,
|
|
85
|
+
// modification time (2 bytes time, 2 bytes date)
|
|
86
|
+
CENCRC: 16,
|
|
87
|
+
// uncompressed file crc-32 value
|
|
88
|
+
CENSIZ: 20,
|
|
89
|
+
// compressed size
|
|
90
|
+
CENLEN: 24,
|
|
91
|
+
// uncompressed size
|
|
92
|
+
CENNAM: 28,
|
|
93
|
+
// filename length
|
|
94
|
+
CENEXT: 30,
|
|
95
|
+
// extra field length
|
|
96
|
+
CENCOM: 32,
|
|
97
|
+
// file comment length
|
|
98
|
+
CENDSK: 34,
|
|
99
|
+
// volume number start
|
|
100
|
+
CENATT: 36,
|
|
101
|
+
// internal file attributes
|
|
102
|
+
CENATX: 38,
|
|
103
|
+
// external file attributes (host system dependent)
|
|
104
|
+
CENOFF: 42,
|
|
105
|
+
// LOC header offset
|
|
106
|
+
/* The entries in the end of central directory */
|
|
107
|
+
ENDHDR: 22,
|
|
108
|
+
// END header size
|
|
109
|
+
ENDSIG: 101010256,
|
|
110
|
+
// "PK\005\006"
|
|
111
|
+
ENDSUB: 8,
|
|
112
|
+
// number of entries on this disk
|
|
113
|
+
ENDTOT: 10,
|
|
114
|
+
// total number of entries
|
|
115
|
+
ENDSIZ: 12,
|
|
116
|
+
// central directory size in bytes
|
|
117
|
+
ENDOFF: 16,
|
|
118
|
+
// offset of first CEN header
|
|
119
|
+
ENDCOM: 20,
|
|
120
|
+
// zip file comment length
|
|
121
|
+
END64HDR: 20,
|
|
122
|
+
// zip64 END header size
|
|
123
|
+
END64SIG: 117853008,
|
|
124
|
+
// zip64 Locator signature, "PK\006\007"
|
|
125
|
+
END64START: 4,
|
|
126
|
+
// number of the disk with the start of the zip64
|
|
127
|
+
END64OFF: 8,
|
|
128
|
+
// relative offset of the zip64 end of central directory
|
|
129
|
+
END64NUMDISKS: 16,
|
|
130
|
+
// total number of disks
|
|
131
|
+
ZIP64SIG: 101075792,
|
|
132
|
+
// zip64 signature, "PK\006\006"
|
|
133
|
+
ZIP64HDR: 56,
|
|
134
|
+
// zip64 record minimum size
|
|
135
|
+
ZIP64LEAD: 12,
|
|
136
|
+
// leading bytes at the start of the record, not counted by the value stored in ZIP64SIZE
|
|
137
|
+
ZIP64SIZE: 4,
|
|
138
|
+
// zip64 size of the central directory record
|
|
139
|
+
ZIP64VEM: 12,
|
|
140
|
+
// zip64 version made by
|
|
141
|
+
ZIP64VER: 14,
|
|
142
|
+
// zip64 version needed to extract
|
|
143
|
+
ZIP64DSK: 16,
|
|
144
|
+
// zip64 number of this disk
|
|
145
|
+
ZIP64DSKDIR: 20,
|
|
146
|
+
// number of the disk with the start of the record directory
|
|
147
|
+
ZIP64SUB: 24,
|
|
148
|
+
// number of entries on this disk
|
|
149
|
+
ZIP64TOT: 32,
|
|
150
|
+
// total number of entries
|
|
151
|
+
ZIP64SIZB: 40,
|
|
152
|
+
// zip64 central directory size in bytes
|
|
153
|
+
ZIP64OFF: 48,
|
|
154
|
+
// offset of start of central directory with respect to the starting disk number
|
|
155
|
+
ZIP64EXTRA: 56,
|
|
156
|
+
// extensible data sector
|
|
157
|
+
/* Compression methods */
|
|
158
|
+
STORED: 0,
|
|
159
|
+
// no compression
|
|
160
|
+
SHRUNK: 1,
|
|
161
|
+
// shrunk
|
|
162
|
+
REDUCED1: 2,
|
|
163
|
+
// reduced with compression factor 1
|
|
164
|
+
REDUCED2: 3,
|
|
165
|
+
// reduced with compression factor 2
|
|
166
|
+
REDUCED3: 4,
|
|
167
|
+
// reduced with compression factor 3
|
|
168
|
+
REDUCED4: 5,
|
|
169
|
+
// reduced with compression factor 4
|
|
170
|
+
IMPLODED: 6,
|
|
171
|
+
// imploded
|
|
172
|
+
// 7 reserved for Tokenizing compression algorithm
|
|
173
|
+
DEFLATED: 8,
|
|
174
|
+
// deflated
|
|
175
|
+
ENHANCED_DEFLATED: 9,
|
|
176
|
+
// enhanced deflated
|
|
177
|
+
PKWARE: 10,
|
|
178
|
+
// PKWare DCL imploded
|
|
179
|
+
// 11 reserved by PKWARE
|
|
180
|
+
BZIP2: 12,
|
|
181
|
+
// compressed using BZIP2
|
|
182
|
+
// 13 reserved by PKWARE
|
|
183
|
+
LZMA: 14,
|
|
184
|
+
// LZMA
|
|
185
|
+
// 15-17 reserved by PKWARE
|
|
186
|
+
IBM_TERSE: 18,
|
|
187
|
+
// compressed using IBM TERSE
|
|
188
|
+
IBM_LZ77: 19,
|
|
189
|
+
// IBM LZ77 z
|
|
190
|
+
AES_ENCRYPT: 99,
|
|
191
|
+
// WinZIP AES encryption method
|
|
192
|
+
/* General purpose bit flag */
|
|
193
|
+
// values can obtained with expression 2**bitnr
|
|
194
|
+
FLG_ENC: 1,
|
|
195
|
+
// Bit 0: encrypted file
|
|
196
|
+
FLG_COMP1: 2,
|
|
197
|
+
// Bit 1, compression option
|
|
198
|
+
FLG_COMP2: 4,
|
|
199
|
+
// Bit 2, compression option
|
|
200
|
+
FLG_DESC: 8,
|
|
201
|
+
// Bit 3, data descriptor
|
|
202
|
+
FLG_ENH: 16,
|
|
203
|
+
// Bit 4, enhanced deflating
|
|
204
|
+
FLG_PATCH: 32,
|
|
205
|
+
// Bit 5, indicates that the file is compressed patched data.
|
|
206
|
+
FLG_STR: 64,
|
|
207
|
+
// Bit 6, strong encryption (patented)
|
|
208
|
+
// Bits 7-10: Currently unused.
|
|
209
|
+
FLG_EFS: 2048,
|
|
210
|
+
// Bit 11: Language encoding flag (EFS)
|
|
211
|
+
// Bit 12: Reserved by PKWARE for enhanced compression.
|
|
212
|
+
// Bit 13: encrypted the Central Directory (patented).
|
|
213
|
+
// Bits 14-15: Reserved by PKWARE.
|
|
214
|
+
FLG_MSK: 4096,
|
|
215
|
+
// mask header values
|
|
216
|
+
/* Load type */
|
|
217
|
+
FILE: 2,
|
|
218
|
+
BUFFER: 1,
|
|
219
|
+
NONE: 0,
|
|
220
|
+
/* 4.5 Extensible data fields */
|
|
221
|
+
EF_ID: 0,
|
|
222
|
+
EF_SIZE: 2,
|
|
223
|
+
/* Header IDs */
|
|
224
|
+
ID_ZIP64: 1,
|
|
225
|
+
ID_AVINFO: 7,
|
|
226
|
+
ID_PFS: 8,
|
|
227
|
+
ID_OS2: 9,
|
|
228
|
+
ID_NTFS: 10,
|
|
229
|
+
ID_OPENVMS: 12,
|
|
230
|
+
ID_UNIX: 13,
|
|
231
|
+
ID_FORK: 14,
|
|
232
|
+
ID_PATCH: 15,
|
|
233
|
+
ID_X509_PKCS7: 20,
|
|
234
|
+
ID_X509_CERTID_F: 21,
|
|
235
|
+
ID_X509_CERTID_C: 22,
|
|
236
|
+
ID_STRONGENC: 23,
|
|
237
|
+
ID_RECORD_MGT: 24,
|
|
238
|
+
ID_X509_PKCS7_RL: 25,
|
|
239
|
+
ID_IBM1: 101,
|
|
240
|
+
ID_IBM2: 102,
|
|
241
|
+
ID_POSZIP: 18064,
|
|
242
|
+
EF_ZIP64_OR_32: 4294967295,
|
|
243
|
+
EF_ZIP64_OR_16: 65535,
|
|
244
|
+
EF_ZIP64_SUNCOMP: 0,
|
|
245
|
+
EF_ZIP64_SCOMP: 8,
|
|
246
|
+
EF_ZIP64_RHO: 16,
|
|
247
|
+
EF_ZIP64_DSN: 24
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// node_modules/adm-zip/util/errors.js
|
|
253
|
+
var require_errors = __commonJS({
|
|
254
|
+
"node_modules/adm-zip/util/errors.js"(exports) {
|
|
255
|
+
var errors = {
|
|
256
|
+
/* Header error messages */
|
|
257
|
+
INVALID_LOC: "Invalid LOC header (bad signature)",
|
|
258
|
+
INVALID_CEN: "Invalid CEN header (bad signature)",
|
|
259
|
+
INVALID_END: "Invalid END header (bad signature)",
|
|
260
|
+
/* Descriptor */
|
|
261
|
+
DESCRIPTOR_NOT_EXIST: "No descriptor present",
|
|
262
|
+
DESCRIPTOR_UNKNOWN: "Unknown descriptor format",
|
|
263
|
+
DESCRIPTOR_FAULTY: "Descriptor data is malformed",
|
|
264
|
+
/* ZipEntry error messages*/
|
|
265
|
+
NO_DATA: "Nothing to decompress",
|
|
266
|
+
BAD_CRC: "CRC32 checksum failed {0}",
|
|
267
|
+
FILE_IN_THE_WAY: "There is a file in the way: {0}",
|
|
268
|
+
UNKNOWN_METHOD: "Invalid/unsupported compression method",
|
|
269
|
+
/* Inflater error messages */
|
|
270
|
+
AVAIL_DATA: "inflate::Available inflate data did not terminate",
|
|
271
|
+
INVALID_DISTANCE: "inflate::Invalid literal/length or distance code in fixed or dynamic block",
|
|
272
|
+
TO_MANY_CODES: "inflate::Dynamic block code description: too many length or distance codes",
|
|
273
|
+
INVALID_REPEAT_LEN: "inflate::Dynamic block code description: repeat more than specified lengths",
|
|
274
|
+
INVALID_REPEAT_FIRST: "inflate::Dynamic block code description: repeat lengths with no first length",
|
|
275
|
+
INCOMPLETE_CODES: "inflate::Dynamic block code description: code lengths codes incomplete",
|
|
276
|
+
INVALID_DYN_DISTANCE: "inflate::Dynamic block code description: invalid distance code lengths",
|
|
277
|
+
INVALID_CODES_LEN: "inflate::Dynamic block code description: invalid literal/length code lengths",
|
|
278
|
+
INVALID_STORE_BLOCK: "inflate::Stored block length did not match one's complement",
|
|
279
|
+
INVALID_BLOCK_TYPE: "inflate::Invalid block type (type == 3)",
|
|
280
|
+
/* ADM-ZIP error messages */
|
|
281
|
+
CANT_EXTRACT_FILE: "Could not extract the file",
|
|
282
|
+
CANT_OVERRIDE: "Target file already exists",
|
|
283
|
+
DISK_ENTRY_TOO_LARGE: "Number of disk entries is too large",
|
|
284
|
+
NO_ZIP: "No zip file was loaded",
|
|
285
|
+
NO_ENTRY: "Entry doesn't exist",
|
|
286
|
+
DIRECTORY_CONTENT_ERROR: "A directory cannot have content",
|
|
287
|
+
FILE_NOT_FOUND: 'File not found: "{0}"',
|
|
288
|
+
NOT_IMPLEMENTED: "Not implemented",
|
|
289
|
+
INVALID_FILENAME: "Invalid filename",
|
|
290
|
+
INVALID_FORMAT: "Invalid or unsupported zip format. No END header found",
|
|
291
|
+
INVALID_PASS_PARAM: "Incompatible password parameter",
|
|
292
|
+
WRONG_PASSWORD: "Wrong Password",
|
|
293
|
+
/* ADM-ZIP */
|
|
294
|
+
COMMENT_TOO_LONG: "Comment is too long",
|
|
295
|
+
// Comment can be max 65535 bytes long (NOTE: some non-US characters may take more space)
|
|
296
|
+
EXTRA_FIELD_PARSE_ERROR: "Extra field parsing error"
|
|
297
|
+
};
|
|
298
|
+
function E(message) {
|
|
299
|
+
return function(...args) {
|
|
300
|
+
if (args.length) {
|
|
301
|
+
message = message.replace(/\{(\d)\}/g, (_, n) => args[n] || "");
|
|
302
|
+
}
|
|
303
|
+
return new Error("ADM-ZIP: " + message);
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
for (const msg of Object.keys(errors)) {
|
|
307
|
+
exports[msg] = E(errors[msg]);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// node_modules/adm-zip/util/utils.js
|
|
313
|
+
var require_utils = __commonJS({
|
|
314
|
+
"node_modules/adm-zip/util/utils.js"(exports, module) {
|
|
315
|
+
var fsystem = __require("fs");
|
|
316
|
+
var pth = __require("path");
|
|
317
|
+
var Constants = require_constants();
|
|
318
|
+
var Errors = require_errors();
|
|
319
|
+
var isWin = typeof process === "object" && "win32" === process.platform;
|
|
320
|
+
var is_Obj = (obj) => typeof obj === "object" && obj !== null;
|
|
321
|
+
var crcTable = new Uint32Array(256).map((t, c) => {
|
|
322
|
+
for (let k = 0; k < 8; k++) {
|
|
323
|
+
if ((c & 1) !== 0) {
|
|
324
|
+
c = 3988292384 ^ c >>> 1;
|
|
325
|
+
} else {
|
|
326
|
+
c >>>= 1;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return c >>> 0;
|
|
330
|
+
});
|
|
331
|
+
function Utils(opts) {
|
|
332
|
+
this.sep = pth.sep;
|
|
333
|
+
this.fs = fsystem;
|
|
334
|
+
if (is_Obj(opts)) {
|
|
335
|
+
if (is_Obj(opts.fs) && typeof opts.fs.statSync === "function") {
|
|
336
|
+
this.fs = opts.fs;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
module.exports = Utils;
|
|
341
|
+
Utils.prototype.makeDir = function(folder) {
|
|
342
|
+
const self = this;
|
|
343
|
+
function mkdirSync(fpath) {
|
|
344
|
+
let resolvedPath = fpath.split(self.sep)[0];
|
|
345
|
+
fpath.split(self.sep).forEach(function(name) {
|
|
346
|
+
if (!name || name.substr(-1, 1) === ":") return;
|
|
347
|
+
resolvedPath += self.sep + name;
|
|
348
|
+
var stat;
|
|
349
|
+
try {
|
|
350
|
+
stat = self.fs.statSync(resolvedPath);
|
|
351
|
+
} catch (e) {
|
|
352
|
+
if (e.message && e.message.startsWith("ENOENT")) {
|
|
353
|
+
self.fs.mkdirSync(resolvedPath);
|
|
354
|
+
} else {
|
|
355
|
+
throw e;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (stat && stat.isFile()) throw Errors.FILE_IN_THE_WAY(`"${resolvedPath}"`);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
mkdirSync(folder);
|
|
362
|
+
};
|
|
363
|
+
Utils.prototype.writeFileTo = function(path12, content, overwrite, attr) {
|
|
364
|
+
const self = this;
|
|
365
|
+
if (self.fs.existsSync(path12)) {
|
|
366
|
+
if (!overwrite) return false;
|
|
367
|
+
var stat = self.fs.statSync(path12);
|
|
368
|
+
if (stat.isDirectory()) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
var folder = pth.dirname(path12);
|
|
373
|
+
if (!self.fs.existsSync(folder)) {
|
|
374
|
+
self.makeDir(folder);
|
|
375
|
+
}
|
|
376
|
+
var fd;
|
|
377
|
+
try {
|
|
378
|
+
fd = self.fs.openSync(path12, "w", 438);
|
|
379
|
+
} catch (e) {
|
|
380
|
+
self.fs.chmodSync(path12, 438);
|
|
381
|
+
fd = self.fs.openSync(path12, "w", 438);
|
|
382
|
+
}
|
|
383
|
+
if (fd) {
|
|
384
|
+
try {
|
|
385
|
+
self.fs.writeSync(fd, content, 0, content.length, 0);
|
|
386
|
+
} finally {
|
|
387
|
+
self.fs.closeSync(fd);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
self.fs.chmodSync(path12, attr || 438);
|
|
391
|
+
return true;
|
|
392
|
+
};
|
|
393
|
+
Utils.prototype.writeFileToAsync = function(path12, content, overwrite, attr, callback) {
|
|
394
|
+
if (typeof attr === "function") {
|
|
395
|
+
callback = attr;
|
|
396
|
+
attr = void 0;
|
|
397
|
+
}
|
|
398
|
+
const self = this;
|
|
399
|
+
self.fs.exists(path12, function(exist) {
|
|
400
|
+
if (exist && !overwrite) return callback(false);
|
|
401
|
+
self.fs.stat(path12, function(err, stat) {
|
|
402
|
+
if (exist && stat && stat.isDirectory()) {
|
|
403
|
+
return callback(false);
|
|
404
|
+
}
|
|
405
|
+
var folder = pth.dirname(path12);
|
|
406
|
+
self.fs.exists(folder, function(exists) {
|
|
407
|
+
if (!exists) {
|
|
408
|
+
try {
|
|
409
|
+
self.makeDir(folder);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
return callback(false);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const writeToFd = function(fd) {
|
|
415
|
+
self.fs.write(fd, content, 0, content.length, 0, function(writeErr) {
|
|
416
|
+
self.fs.close(fd, function() {
|
|
417
|
+
if (writeErr) return callback(false);
|
|
418
|
+
self.fs.chmod(path12, attr || 438, function() {
|
|
419
|
+
callback(true);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
};
|
|
424
|
+
self.fs.open(path12, "w", 438, function(err2, fd) {
|
|
425
|
+
if (err2) {
|
|
426
|
+
self.fs.chmod(path12, 438, function() {
|
|
427
|
+
self.fs.open(path12, "w", 438, function(retryErr, fd2) {
|
|
428
|
+
if (retryErr || !fd2) return callback(false);
|
|
429
|
+
writeToFd(fd2);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
} else if (fd) {
|
|
433
|
+
writeToFd(fd);
|
|
434
|
+
} else {
|
|
435
|
+
callback(false);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
Utils.prototype.findFiles = function(path12) {
|
|
443
|
+
const self = this;
|
|
444
|
+
function findSync(dir, pattern, recursive, visited) {
|
|
445
|
+
if (typeof pattern === "boolean") {
|
|
446
|
+
recursive = pattern;
|
|
447
|
+
pattern = void 0;
|
|
448
|
+
}
|
|
449
|
+
let files = [];
|
|
450
|
+
self.fs.readdirSync(dir).forEach(function(file) {
|
|
451
|
+
const path13 = pth.join(dir, file);
|
|
452
|
+
const stat = self.fs.statSync(path13);
|
|
453
|
+
if (!pattern || pattern.test(path13)) {
|
|
454
|
+
files.push(pth.normalize(path13) + (stat.isDirectory() ? self.sep : ""));
|
|
455
|
+
}
|
|
456
|
+
if (stat.isDirectory() && recursive) {
|
|
457
|
+
const realDir = self.fs.realpathSync(path13);
|
|
458
|
+
if (!visited.has(realDir)) {
|
|
459
|
+
visited.add(realDir);
|
|
460
|
+
files = files.concat(findSync(path13, pattern, recursive, visited));
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
return files;
|
|
465
|
+
}
|
|
466
|
+
return findSync(path12, void 0, true, /* @__PURE__ */ new Set([self.fs.realpathSync(path12)]));
|
|
467
|
+
};
|
|
468
|
+
Utils.prototype.findFilesAsync = function(dir, cb) {
|
|
469
|
+
const self = this;
|
|
470
|
+
const results = [];
|
|
471
|
+
let finished = false;
|
|
472
|
+
const finish = function(err) {
|
|
473
|
+
if (finished) return;
|
|
474
|
+
finished = true;
|
|
475
|
+
cb(err, err ? void 0 : results);
|
|
476
|
+
};
|
|
477
|
+
const walk = function(dir2, visited, done) {
|
|
478
|
+
self.fs.readdir(dir2, function(err, list) {
|
|
479
|
+
if (err) return done(err);
|
|
480
|
+
let pending = list.length;
|
|
481
|
+
if (!pending) return done();
|
|
482
|
+
list.forEach(function(name) {
|
|
483
|
+
const file = pth.join(dir2, name);
|
|
484
|
+
self.fs.stat(file, function(err2, stat) {
|
|
485
|
+
if (err2) return done(err2);
|
|
486
|
+
if (!stat) {
|
|
487
|
+
if (!--pending) done();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
results.push(pth.normalize(file) + (stat.isDirectory() ? self.sep : ""));
|
|
491
|
+
if (!stat.isDirectory()) {
|
|
492
|
+
if (!--pending) done();
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
self.fs.realpath(file, function(err3, realDir) {
|
|
496
|
+
if (err3) return done(err3);
|
|
497
|
+
if (visited.has(realDir)) {
|
|
498
|
+
if (!--pending) done();
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
visited.add(realDir);
|
|
502
|
+
walk(file, visited, function(err4) {
|
|
503
|
+
if (err4) return done(err4);
|
|
504
|
+
if (!--pending) done();
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
};
|
|
511
|
+
self.fs.realpath(dir, function(err, realDir) {
|
|
512
|
+
if (err) return finish(err);
|
|
513
|
+
walk(dir, /* @__PURE__ */ new Set([realDir]), finish);
|
|
514
|
+
});
|
|
515
|
+
};
|
|
516
|
+
Utils.prototype.getAttributes = function() {
|
|
517
|
+
};
|
|
518
|
+
Utils.prototype.setAttributes = function() {
|
|
519
|
+
};
|
|
520
|
+
Utils.crc32update = function(crc, byte) {
|
|
521
|
+
return crcTable[(crc ^ byte) & 255] ^ crc >>> 8;
|
|
522
|
+
};
|
|
523
|
+
Utils.crc32 = function(buf) {
|
|
524
|
+
if (typeof buf === "string") {
|
|
525
|
+
buf = Buffer.from(buf, "utf8");
|
|
526
|
+
}
|
|
527
|
+
let len = buf.length;
|
|
528
|
+
let crc = ~0;
|
|
529
|
+
for (let off = 0; off < len; ) crc = Utils.crc32update(crc, buf[off++]);
|
|
530
|
+
return ~crc >>> 0;
|
|
531
|
+
};
|
|
532
|
+
Utils.methodToString = function(method) {
|
|
533
|
+
switch (method) {
|
|
534
|
+
case Constants.STORED:
|
|
535
|
+
return "STORED (" + method + ")";
|
|
536
|
+
case Constants.DEFLATED:
|
|
537
|
+
return "DEFLATED (" + method + ")";
|
|
538
|
+
default:
|
|
539
|
+
return "UNSUPPORTED (" + method + ")";
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
Utils.canonical = function(path12) {
|
|
543
|
+
if (!path12) return "";
|
|
544
|
+
const safeSuffix = pth.posix.normalize("/" + path12.split("\\").join("/"));
|
|
545
|
+
return pth.join(".", safeSuffix);
|
|
546
|
+
};
|
|
547
|
+
Utils.zipnamefix = function(path12) {
|
|
548
|
+
if (!path12) return "";
|
|
549
|
+
const safeSuffix = pth.posix.normalize("/" + path12.split("\\").join("/"));
|
|
550
|
+
return pth.posix.join(".", safeSuffix);
|
|
551
|
+
};
|
|
552
|
+
Utils.findLast = function(arr, callback) {
|
|
553
|
+
if (!Array.isArray(arr)) throw new TypeError("arr is not array");
|
|
554
|
+
const len = arr.length >>> 0;
|
|
555
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
556
|
+
if (callback(arr[i], i, arr)) {
|
|
557
|
+
return arr[i];
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return void 0;
|
|
561
|
+
};
|
|
562
|
+
Utils.sanitize = function(prefix, name) {
|
|
563
|
+
prefix = pth.resolve(pth.normalize(prefix));
|
|
564
|
+
var parts = name.split("/");
|
|
565
|
+
for (var i = 0, l = parts.length; i < l; i++) {
|
|
566
|
+
var path12 = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep)));
|
|
567
|
+
if (path12 === prefix || path12.startsWith(prefix + pth.sep)) {
|
|
568
|
+
return path12;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return pth.normalize(pth.join(prefix, pth.basename(name)));
|
|
572
|
+
};
|
|
573
|
+
Utils.toBuffer = function toBuffer(input, encoder) {
|
|
574
|
+
if (Buffer.isBuffer(input)) {
|
|
575
|
+
return input;
|
|
576
|
+
} else if (input instanceof Uint8Array) {
|
|
577
|
+
return Buffer.from(input);
|
|
578
|
+
} else {
|
|
579
|
+
return typeof input === "string" ? encoder(input) : Buffer.alloc(0);
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
Utils.readBigUInt64LE = function(buffer, index) {
|
|
583
|
+
const lo = buffer.readUInt32LE(index);
|
|
584
|
+
const hi = buffer.readUInt32LE(index + 4);
|
|
585
|
+
return hi * 4294967296 + lo;
|
|
586
|
+
};
|
|
587
|
+
Utils.writeBigUInt64LE = function(buffer, value, index) {
|
|
588
|
+
const lo = value >>> 0;
|
|
589
|
+
const hi = Math.floor(value / 4294967296) >>> 0;
|
|
590
|
+
buffer.writeUInt32LE(lo, index);
|
|
591
|
+
buffer.writeUInt32LE(hi, index + 4);
|
|
592
|
+
};
|
|
593
|
+
Utils.fromDOS2Date = function(val) {
|
|
594
|
+
return new Date((val >> 25 & 127) + 1980, Math.max((val >> 21 & 15) - 1, 0), Math.max(val >> 16 & 31, 1), val >> 11 & 31, val >> 5 & 63, (val & 31) << 1);
|
|
595
|
+
};
|
|
596
|
+
Utils.fromDate2DOS = function(val) {
|
|
597
|
+
let date = 0;
|
|
598
|
+
let time = 0;
|
|
599
|
+
if (val.getFullYear() > 1979) {
|
|
600
|
+
date = (val.getFullYear() - 1980 & 127) << 9 | val.getMonth() + 1 << 5 | val.getDate();
|
|
601
|
+
time = val.getHours() << 11 | val.getMinutes() << 5 | val.getSeconds() >> 1;
|
|
602
|
+
}
|
|
603
|
+
return date << 16 | time;
|
|
604
|
+
};
|
|
605
|
+
Utils.isWin = isWin;
|
|
606
|
+
Utils.crcTable = crcTable;
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
// node_modules/adm-zip/util/fattr.js
|
|
611
|
+
var require_fattr = __commonJS({
|
|
612
|
+
"node_modules/adm-zip/util/fattr.js"(exports, module) {
|
|
613
|
+
var pth = __require("path");
|
|
614
|
+
module.exports = function(path12, { fs: fs10 }) {
|
|
615
|
+
var _path = path12 || "", _obj = newAttr(), _stat = null;
|
|
616
|
+
function newAttr() {
|
|
617
|
+
return {
|
|
618
|
+
directory: false,
|
|
619
|
+
readonly: false,
|
|
620
|
+
hidden: false,
|
|
621
|
+
executable: false,
|
|
622
|
+
mtime: 0,
|
|
623
|
+
atime: 0
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (_path && fs10.existsSync(_path)) {
|
|
627
|
+
_stat = fs10.statSync(_path);
|
|
628
|
+
_obj.directory = _stat.isDirectory();
|
|
629
|
+
_obj.mtime = _stat.mtime;
|
|
630
|
+
_obj.atime = _stat.atime;
|
|
631
|
+
_obj.executable = (73 & _stat.mode) !== 0;
|
|
632
|
+
_obj.readonly = (128 & _stat.mode) === 0;
|
|
633
|
+
_obj.hidden = pth.basename(_path)[0] === ".";
|
|
634
|
+
} else {
|
|
635
|
+
console.warn("Invalid path: " + _path);
|
|
636
|
+
}
|
|
637
|
+
return {
|
|
638
|
+
get directory() {
|
|
639
|
+
return _obj.directory;
|
|
640
|
+
},
|
|
641
|
+
get readOnly() {
|
|
642
|
+
return _obj.readonly;
|
|
643
|
+
},
|
|
644
|
+
get hidden() {
|
|
645
|
+
return _obj.hidden;
|
|
646
|
+
},
|
|
647
|
+
get mtime() {
|
|
648
|
+
return _obj.mtime;
|
|
649
|
+
},
|
|
650
|
+
get atime() {
|
|
651
|
+
return _obj.atime;
|
|
652
|
+
},
|
|
653
|
+
get executable() {
|
|
654
|
+
return _obj.executable;
|
|
655
|
+
},
|
|
656
|
+
decodeAttributes: function() {
|
|
657
|
+
},
|
|
658
|
+
encodeAttributes: function() {
|
|
659
|
+
},
|
|
660
|
+
toJSON: function() {
|
|
661
|
+
return {
|
|
662
|
+
path: _path,
|
|
663
|
+
isDirectory: _obj.directory,
|
|
664
|
+
isReadOnly: _obj.readonly,
|
|
665
|
+
isHidden: _obj.hidden,
|
|
666
|
+
isExecutable: _obj.executable,
|
|
667
|
+
mTime: _obj.mtime,
|
|
668
|
+
aTime: _obj.atime
|
|
669
|
+
};
|
|
670
|
+
},
|
|
671
|
+
toString: function() {
|
|
672
|
+
return JSON.stringify(this.toJSON(), null, " ");
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// node_modules/adm-zip/util/decoder.js
|
|
680
|
+
var require_decoder = __commonJS({
|
|
681
|
+
"node_modules/adm-zip/util/decoder.js"(exports, module) {
|
|
682
|
+
module.exports = {
|
|
683
|
+
efs: true,
|
|
684
|
+
encode: (data) => Buffer.from(data, "utf8"),
|
|
685
|
+
decode: (data) => data.toString("utf8")
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
// node_modules/adm-zip/util/index.js
|
|
691
|
+
var require_util = __commonJS({
|
|
692
|
+
"node_modules/adm-zip/util/index.js"(exports, module) {
|
|
693
|
+
module.exports = require_utils();
|
|
694
|
+
module.exports.Constants = require_constants();
|
|
695
|
+
module.exports.Errors = require_errors();
|
|
696
|
+
module.exports.FileAttr = require_fattr();
|
|
697
|
+
module.exports.decoder = require_decoder();
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
// node_modules/adm-zip/headers/entryHeader.js
|
|
702
|
+
var require_entryHeader = __commonJS({
|
|
703
|
+
"node_modules/adm-zip/headers/entryHeader.js"(exports, module) {
|
|
704
|
+
var Utils = require_util();
|
|
705
|
+
var Constants = Utils.Constants;
|
|
706
|
+
module.exports = function() {
|
|
707
|
+
var _verMade = 20, _version = 10, _flags = 0, _method = 0, _time = 0, _crc = 0, _compressedSize = 0, _size = 0, _fnameLen = 0, _extraLen = 0, _comLen = 0, _diskStart = 0, _inattr = 0, _attr = 0, _offset = 0;
|
|
708
|
+
_verMade |= Utils.isWin ? 2560 : 768;
|
|
709
|
+
_flags |= Constants.FLG_EFS;
|
|
710
|
+
const _localHeader = {
|
|
711
|
+
extraLen: 0
|
|
712
|
+
};
|
|
713
|
+
const uint32 = (val) => Math.max(0, val) >>> 0;
|
|
714
|
+
const uint16 = (val) => Math.max(0, val) & 65535;
|
|
715
|
+
const uint8 = (val) => Math.max(0, val) & 255;
|
|
716
|
+
_time = Utils.fromDate2DOS(/* @__PURE__ */ new Date());
|
|
717
|
+
return {
|
|
718
|
+
get made() {
|
|
719
|
+
return _verMade;
|
|
720
|
+
},
|
|
721
|
+
set made(val) {
|
|
722
|
+
_verMade = val;
|
|
723
|
+
},
|
|
724
|
+
get version() {
|
|
725
|
+
return _version;
|
|
726
|
+
},
|
|
727
|
+
set version(val) {
|
|
728
|
+
_version = val;
|
|
729
|
+
},
|
|
730
|
+
get flags() {
|
|
731
|
+
return _flags;
|
|
732
|
+
},
|
|
733
|
+
set flags(val) {
|
|
734
|
+
_flags = val;
|
|
735
|
+
},
|
|
736
|
+
get flags_efs() {
|
|
737
|
+
return (_flags & Constants.FLG_EFS) > 0;
|
|
738
|
+
},
|
|
739
|
+
set flags_efs(val) {
|
|
740
|
+
if (val) {
|
|
741
|
+
_flags |= Constants.FLG_EFS;
|
|
742
|
+
} else {
|
|
743
|
+
_flags &= ~Constants.FLG_EFS;
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
get flags_desc() {
|
|
747
|
+
return (_flags & Constants.FLG_DESC) > 0;
|
|
748
|
+
},
|
|
749
|
+
set flags_desc(val) {
|
|
750
|
+
if (val) {
|
|
751
|
+
_flags |= Constants.FLG_DESC;
|
|
752
|
+
} else {
|
|
753
|
+
_flags &= ~Constants.FLG_DESC;
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
get method() {
|
|
757
|
+
return _method;
|
|
758
|
+
},
|
|
759
|
+
set method(val) {
|
|
760
|
+
switch (val) {
|
|
761
|
+
case Constants.STORED:
|
|
762
|
+
this.version = 10;
|
|
763
|
+
break;
|
|
764
|
+
case Constants.DEFLATED:
|
|
765
|
+
default:
|
|
766
|
+
this.version = 20;
|
|
767
|
+
}
|
|
768
|
+
_method = val;
|
|
769
|
+
},
|
|
770
|
+
get time() {
|
|
771
|
+
return Utils.fromDOS2Date(this.timeval);
|
|
772
|
+
},
|
|
773
|
+
set time(val) {
|
|
774
|
+
val = new Date(val);
|
|
775
|
+
this.timeval = Utils.fromDate2DOS(val);
|
|
776
|
+
},
|
|
777
|
+
get timeval() {
|
|
778
|
+
return _time;
|
|
779
|
+
},
|
|
780
|
+
set timeval(val) {
|
|
781
|
+
_time = uint32(val);
|
|
782
|
+
},
|
|
783
|
+
get timeHighByte() {
|
|
784
|
+
return uint8(_time >>> 8);
|
|
785
|
+
},
|
|
786
|
+
get crc() {
|
|
787
|
+
return _crc;
|
|
788
|
+
},
|
|
789
|
+
set crc(val) {
|
|
790
|
+
_crc = uint32(val);
|
|
791
|
+
},
|
|
792
|
+
get compressedSize() {
|
|
793
|
+
return _compressedSize;
|
|
794
|
+
},
|
|
795
|
+
set compressedSize(val) {
|
|
796
|
+
_compressedSize = uint32(val);
|
|
797
|
+
},
|
|
798
|
+
get size() {
|
|
799
|
+
return _size;
|
|
800
|
+
},
|
|
801
|
+
set size(val) {
|
|
802
|
+
_size = uint32(val);
|
|
803
|
+
},
|
|
804
|
+
get fileNameLength() {
|
|
805
|
+
return _fnameLen;
|
|
806
|
+
},
|
|
807
|
+
set fileNameLength(val) {
|
|
808
|
+
_fnameLen = val;
|
|
809
|
+
},
|
|
810
|
+
get extraLength() {
|
|
811
|
+
return _extraLen;
|
|
812
|
+
},
|
|
813
|
+
set extraLength(val) {
|
|
814
|
+
_extraLen = val;
|
|
815
|
+
},
|
|
816
|
+
get extraLocalLength() {
|
|
817
|
+
return _localHeader.extraLen;
|
|
818
|
+
},
|
|
819
|
+
set extraLocalLength(val) {
|
|
820
|
+
_localHeader.extraLen = val;
|
|
821
|
+
},
|
|
822
|
+
get commentLength() {
|
|
823
|
+
return _comLen;
|
|
824
|
+
},
|
|
825
|
+
set commentLength(val) {
|
|
826
|
+
_comLen = val;
|
|
827
|
+
},
|
|
828
|
+
get diskNumStart() {
|
|
829
|
+
return _diskStart;
|
|
830
|
+
},
|
|
831
|
+
set diskNumStart(val) {
|
|
832
|
+
_diskStart = uint32(val);
|
|
833
|
+
},
|
|
834
|
+
get inAttr() {
|
|
835
|
+
return _inattr;
|
|
836
|
+
},
|
|
837
|
+
set inAttr(val) {
|
|
838
|
+
_inattr = uint32(val);
|
|
839
|
+
},
|
|
840
|
+
get attr() {
|
|
841
|
+
return _attr;
|
|
842
|
+
},
|
|
843
|
+
set attr(val) {
|
|
844
|
+
_attr = uint32(val);
|
|
845
|
+
},
|
|
846
|
+
// get Unix file permissions
|
|
847
|
+
get fileAttr() {
|
|
848
|
+
return (_attr || 0) >> 16 & 4095;
|
|
849
|
+
},
|
|
850
|
+
get offset() {
|
|
851
|
+
return _offset;
|
|
852
|
+
},
|
|
853
|
+
set offset(val) {
|
|
854
|
+
_offset = uint32(val);
|
|
855
|
+
},
|
|
856
|
+
get encrypted() {
|
|
857
|
+
return (_flags & Constants.FLG_ENC) === Constants.FLG_ENC;
|
|
858
|
+
},
|
|
859
|
+
get centralHeaderSize() {
|
|
860
|
+
return Constants.CENHDR + _fnameLen + _extraLen + _comLen;
|
|
861
|
+
},
|
|
862
|
+
get realDataOffset() {
|
|
863
|
+
return _offset + Constants.LOCHDR + _localHeader.fnameLen + _localHeader.extraLen;
|
|
864
|
+
},
|
|
865
|
+
get localHeader() {
|
|
866
|
+
return _localHeader;
|
|
867
|
+
},
|
|
868
|
+
loadLocalHeaderFromBinary: function(input) {
|
|
869
|
+
var data = input.slice(_offset, _offset + Constants.LOCHDR);
|
|
870
|
+
if (data.readUInt32LE(0) !== Constants.LOCSIG) {
|
|
871
|
+
throw Utils.Errors.INVALID_LOC();
|
|
872
|
+
}
|
|
873
|
+
_localHeader.version = data.readUInt16LE(Constants.LOCVER);
|
|
874
|
+
_localHeader.flags = data.readUInt16LE(Constants.LOCFLG);
|
|
875
|
+
_localHeader.flags_desc = (_localHeader.flags & Constants.FLG_DESC) > 0;
|
|
876
|
+
_localHeader.method = data.readUInt16LE(Constants.LOCHOW);
|
|
877
|
+
_localHeader.time = data.readUInt32LE(Constants.LOCTIM);
|
|
878
|
+
_localHeader.crc = data.readUInt32LE(Constants.LOCCRC);
|
|
879
|
+
_localHeader.compressedSize = data.readUInt32LE(Constants.LOCSIZ);
|
|
880
|
+
_localHeader.size = data.readUInt32LE(Constants.LOCLEN);
|
|
881
|
+
_localHeader.fnameLen = data.readUInt16LE(Constants.LOCNAM);
|
|
882
|
+
_localHeader.extraLen = data.readUInt16LE(Constants.LOCEXT);
|
|
883
|
+
const extraStart = _offset + Constants.LOCHDR + _localHeader.fnameLen;
|
|
884
|
+
const extraEnd = extraStart + _localHeader.extraLen;
|
|
885
|
+
return input.slice(extraStart, extraEnd);
|
|
886
|
+
},
|
|
887
|
+
loadFromBinary: function(data) {
|
|
888
|
+
if (data.length !== Constants.CENHDR || data.readUInt32LE(0) !== Constants.CENSIG) {
|
|
889
|
+
throw Utils.Errors.INVALID_CEN();
|
|
890
|
+
}
|
|
891
|
+
_verMade = data.readUInt16LE(Constants.CENVEM);
|
|
892
|
+
_version = data.readUInt16LE(Constants.CENVER);
|
|
893
|
+
_flags = data.readUInt16LE(Constants.CENFLG);
|
|
894
|
+
_method = data.readUInt16LE(Constants.CENHOW);
|
|
895
|
+
_time = data.readUInt32LE(Constants.CENTIM);
|
|
896
|
+
_crc = data.readUInt32LE(Constants.CENCRC);
|
|
897
|
+
_compressedSize = data.readUInt32LE(Constants.CENSIZ);
|
|
898
|
+
_size = data.readUInt32LE(Constants.CENLEN);
|
|
899
|
+
_fnameLen = data.readUInt16LE(Constants.CENNAM);
|
|
900
|
+
_extraLen = data.readUInt16LE(Constants.CENEXT);
|
|
901
|
+
_comLen = data.readUInt16LE(Constants.CENCOM);
|
|
902
|
+
_diskStart = data.readUInt16LE(Constants.CENDSK);
|
|
903
|
+
_inattr = data.readUInt16LE(Constants.CENATT);
|
|
904
|
+
_attr = data.readUInt32LE(Constants.CENATX);
|
|
905
|
+
_offset = data.readUInt32LE(Constants.CENOFF);
|
|
906
|
+
},
|
|
907
|
+
localHeaderToBinary: function() {
|
|
908
|
+
var data = Buffer.alloc(Constants.LOCHDR);
|
|
909
|
+
data.writeUInt32LE(Constants.LOCSIG, 0);
|
|
910
|
+
data.writeUInt16LE(_version, Constants.LOCVER);
|
|
911
|
+
data.writeUInt16LE(_flags & ~Constants.FLG_DESC, Constants.LOCFLG);
|
|
912
|
+
data.writeUInt16LE(_method, Constants.LOCHOW);
|
|
913
|
+
data.writeUInt32LE(_time, Constants.LOCTIM);
|
|
914
|
+
data.writeUInt32LE(_crc, Constants.LOCCRC);
|
|
915
|
+
data.writeUInt32LE(_compressedSize, Constants.LOCSIZ);
|
|
916
|
+
data.writeUInt32LE(_size, Constants.LOCLEN);
|
|
917
|
+
data.writeUInt16LE(_fnameLen, Constants.LOCNAM);
|
|
918
|
+
data.writeUInt16LE(_localHeader.extraLen, Constants.LOCEXT);
|
|
919
|
+
return data;
|
|
920
|
+
},
|
|
921
|
+
centralHeaderToBinary: function() {
|
|
922
|
+
var data = Buffer.alloc(Constants.CENHDR + _fnameLen + _extraLen + _comLen);
|
|
923
|
+
data.writeUInt32LE(Constants.CENSIG, 0);
|
|
924
|
+
data.writeUInt16LE(_verMade, Constants.CENVEM);
|
|
925
|
+
data.writeUInt16LE(_version, Constants.CENVER);
|
|
926
|
+
data.writeUInt16LE(_flags & ~Constants.FLG_DESC, Constants.CENFLG);
|
|
927
|
+
data.writeUInt16LE(_method, Constants.CENHOW);
|
|
928
|
+
data.writeUInt32LE(_time, Constants.CENTIM);
|
|
929
|
+
data.writeUInt32LE(_crc, Constants.CENCRC);
|
|
930
|
+
data.writeUInt32LE(_compressedSize, Constants.CENSIZ);
|
|
931
|
+
data.writeUInt32LE(_size, Constants.CENLEN);
|
|
932
|
+
data.writeUInt16LE(_fnameLen, Constants.CENNAM);
|
|
933
|
+
data.writeUInt16LE(_extraLen, Constants.CENEXT);
|
|
934
|
+
data.writeUInt16LE(_comLen, Constants.CENCOM);
|
|
935
|
+
data.writeUInt16LE(_diskStart, Constants.CENDSK);
|
|
936
|
+
data.writeUInt16LE(_inattr, Constants.CENATT);
|
|
937
|
+
data.writeUInt32LE(_attr, Constants.CENATX);
|
|
938
|
+
data.writeUInt32LE(_offset, Constants.CENOFF);
|
|
939
|
+
return data;
|
|
940
|
+
},
|
|
941
|
+
toJSON: function() {
|
|
942
|
+
const bytes = function(nr) {
|
|
943
|
+
return nr + " bytes";
|
|
944
|
+
};
|
|
945
|
+
return {
|
|
946
|
+
made: _verMade,
|
|
947
|
+
version: _version,
|
|
948
|
+
flags: _flags,
|
|
949
|
+
method: Utils.methodToString(_method),
|
|
950
|
+
time: this.time,
|
|
951
|
+
crc: "0x" + _crc.toString(16).toUpperCase(),
|
|
952
|
+
compressedSize: bytes(_compressedSize),
|
|
953
|
+
size: bytes(_size),
|
|
954
|
+
fileNameLength: bytes(_fnameLen),
|
|
955
|
+
extraLength: bytes(_extraLen),
|
|
956
|
+
commentLength: bytes(_comLen),
|
|
957
|
+
diskNumStart: _diskStart,
|
|
958
|
+
inAttr: _inattr,
|
|
959
|
+
attr: _attr,
|
|
960
|
+
offset: _offset,
|
|
961
|
+
centralHeaderSize: bytes(Constants.CENHDR + _fnameLen + _extraLen + _comLen)
|
|
962
|
+
};
|
|
963
|
+
},
|
|
964
|
+
toString: function() {
|
|
965
|
+
return JSON.stringify(this.toJSON(), null, " ");
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
// node_modules/adm-zip/headers/mainHeader.js
|
|
973
|
+
var require_mainHeader = __commonJS({
|
|
974
|
+
"node_modules/adm-zip/headers/mainHeader.js"(exports, module) {
|
|
975
|
+
var Utils = require_util();
|
|
976
|
+
var Constants = Utils.Constants;
|
|
977
|
+
module.exports = function() {
|
|
978
|
+
var _volumeEntries = 0, _totalEntries = 0, _size = 0, _offset = 0, _commentLength = 0;
|
|
979
|
+
const needsZip64 = () => _volumeEntries > Constants.EF_ZIP64_OR_16 || _totalEntries > Constants.EF_ZIP64_OR_16 || _size > Constants.EF_ZIP64_OR_32 || _offset > Constants.EF_ZIP64_OR_32;
|
|
980
|
+
return {
|
|
981
|
+
get diskEntries() {
|
|
982
|
+
return _volumeEntries;
|
|
983
|
+
},
|
|
984
|
+
set diskEntries(val) {
|
|
985
|
+
_volumeEntries = _totalEntries = val;
|
|
986
|
+
},
|
|
987
|
+
get totalEntries() {
|
|
988
|
+
return _totalEntries;
|
|
989
|
+
},
|
|
990
|
+
set totalEntries(val) {
|
|
991
|
+
_totalEntries = _volumeEntries = val;
|
|
992
|
+
},
|
|
993
|
+
get size() {
|
|
994
|
+
return _size;
|
|
995
|
+
},
|
|
996
|
+
set size(val) {
|
|
997
|
+
_size = val;
|
|
998
|
+
},
|
|
999
|
+
get offset() {
|
|
1000
|
+
return _offset;
|
|
1001
|
+
},
|
|
1002
|
+
set offset(val) {
|
|
1003
|
+
_offset = val;
|
|
1004
|
+
},
|
|
1005
|
+
get commentLength() {
|
|
1006
|
+
return _commentLength;
|
|
1007
|
+
},
|
|
1008
|
+
set commentLength(val) {
|
|
1009
|
+
_commentLength = val;
|
|
1010
|
+
},
|
|
1011
|
+
get mainHeaderSize() {
|
|
1012
|
+
return (needsZip64() ? Constants.ZIP64HDR + Constants.END64HDR : 0) + Constants.ENDHDR + _commentLength;
|
|
1013
|
+
},
|
|
1014
|
+
loadFromBinary: function(data) {
|
|
1015
|
+
if ((data.length !== Constants.ENDHDR || data.readUInt32LE(0) !== Constants.ENDSIG) && (data.length < Constants.ZIP64HDR || data.readUInt32LE(0) !== Constants.ZIP64SIG)) {
|
|
1016
|
+
throw Utils.Errors.INVALID_END();
|
|
1017
|
+
}
|
|
1018
|
+
if (data.readUInt32LE(0) === Constants.ENDSIG) {
|
|
1019
|
+
_volumeEntries = data.readUInt16LE(Constants.ENDSUB);
|
|
1020
|
+
_totalEntries = data.readUInt16LE(Constants.ENDTOT);
|
|
1021
|
+
_size = data.readUInt32LE(Constants.ENDSIZ);
|
|
1022
|
+
_offset = data.readUInt32LE(Constants.ENDOFF);
|
|
1023
|
+
_commentLength = data.readUInt16LE(Constants.ENDCOM);
|
|
1024
|
+
} else {
|
|
1025
|
+
_volumeEntries = Utils.readBigUInt64LE(data, Constants.ZIP64SUB);
|
|
1026
|
+
_totalEntries = Utils.readBigUInt64LE(data, Constants.ZIP64TOT);
|
|
1027
|
+
_size = Utils.readBigUInt64LE(data, Constants.ZIP64SIZB);
|
|
1028
|
+
_offset = Utils.readBigUInt64LE(data, Constants.ZIP64OFF);
|
|
1029
|
+
_commentLength = 0;
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
toBinary: function() {
|
|
1033
|
+
if (!needsZip64()) {
|
|
1034
|
+
var b = Buffer.alloc(Constants.ENDHDR + _commentLength);
|
|
1035
|
+
b.writeUInt32LE(Constants.ENDSIG, 0);
|
|
1036
|
+
b.writeUInt32LE(0, 4);
|
|
1037
|
+
b.writeUInt16LE(_volumeEntries, Constants.ENDSUB);
|
|
1038
|
+
b.writeUInt16LE(_totalEntries, Constants.ENDTOT);
|
|
1039
|
+
b.writeUInt32LE(_size, Constants.ENDSIZ);
|
|
1040
|
+
b.writeUInt32LE(_offset, Constants.ENDOFF);
|
|
1041
|
+
b.writeUInt16LE(_commentLength, Constants.ENDCOM);
|
|
1042
|
+
b.fill(" ", Constants.ENDHDR);
|
|
1043
|
+
return b;
|
|
1044
|
+
}
|
|
1045
|
+
var b = Buffer.alloc(this.mainHeaderSize);
|
|
1046
|
+
let offset = 0;
|
|
1047
|
+
b.writeUInt32LE(Constants.ZIP64SIG, offset);
|
|
1048
|
+
Utils.writeBigUInt64LE(b, Constants.ZIP64HDR - Constants.ZIP64LEAD, offset + Constants.ZIP64SIZE);
|
|
1049
|
+
b.writeUInt16LE(45, offset + Constants.ZIP64VEM);
|
|
1050
|
+
b.writeUInt16LE(45, offset + Constants.ZIP64VER);
|
|
1051
|
+
b.writeUInt32LE(0, offset + Constants.ZIP64DSK);
|
|
1052
|
+
b.writeUInt32LE(0, offset + Constants.ZIP64DSKDIR);
|
|
1053
|
+
Utils.writeBigUInt64LE(b, _volumeEntries, offset + Constants.ZIP64SUB);
|
|
1054
|
+
Utils.writeBigUInt64LE(b, _totalEntries, offset + Constants.ZIP64TOT);
|
|
1055
|
+
Utils.writeBigUInt64LE(b, _size, offset + Constants.ZIP64SIZB);
|
|
1056
|
+
Utils.writeBigUInt64LE(b, _offset, offset + Constants.ZIP64OFF);
|
|
1057
|
+
const zip64EndOffset = _offset + _size;
|
|
1058
|
+
offset += Constants.ZIP64HDR;
|
|
1059
|
+
b.writeUInt32LE(Constants.END64SIG, offset);
|
|
1060
|
+
b.writeUInt32LE(0, offset + Constants.END64START);
|
|
1061
|
+
Utils.writeBigUInt64LE(b, zip64EndOffset, offset + Constants.END64OFF);
|
|
1062
|
+
b.writeUInt32LE(1, offset + Constants.END64NUMDISKS);
|
|
1063
|
+
offset += Constants.END64HDR;
|
|
1064
|
+
b.writeUInt32LE(Constants.ENDSIG, offset);
|
|
1065
|
+
b.writeUInt32LE(0, offset + 4);
|
|
1066
|
+
b.writeUInt16LE(Math.min(_volumeEntries, Constants.EF_ZIP64_OR_16), offset + Constants.ENDSUB);
|
|
1067
|
+
b.writeUInt16LE(Math.min(_totalEntries, Constants.EF_ZIP64_OR_16), offset + Constants.ENDTOT);
|
|
1068
|
+
b.writeUInt32LE(Math.min(_size, Constants.EF_ZIP64_OR_32), offset + Constants.ENDSIZ);
|
|
1069
|
+
b.writeUInt32LE(Math.min(_offset, Constants.EF_ZIP64_OR_32), offset + Constants.ENDOFF);
|
|
1070
|
+
b.writeUInt16LE(_commentLength, offset + Constants.ENDCOM);
|
|
1071
|
+
b.fill(" ", offset + Constants.ENDHDR);
|
|
1072
|
+
return b;
|
|
1073
|
+
},
|
|
1074
|
+
toJSON: function() {
|
|
1075
|
+
const offset = function(nr, len) {
|
|
1076
|
+
let offs = nr.toString(16).toUpperCase();
|
|
1077
|
+
while (offs.length < len) offs = "0" + offs;
|
|
1078
|
+
return "0x" + offs;
|
|
1079
|
+
};
|
|
1080
|
+
return {
|
|
1081
|
+
diskEntries: _volumeEntries,
|
|
1082
|
+
totalEntries: _totalEntries,
|
|
1083
|
+
size: _size + " bytes",
|
|
1084
|
+
offset: offset(_offset, 4),
|
|
1085
|
+
commentLength: _commentLength
|
|
1086
|
+
};
|
|
1087
|
+
},
|
|
1088
|
+
toString: function() {
|
|
1089
|
+
return JSON.stringify(this.toJSON(), null, " ");
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
// node_modules/adm-zip/headers/index.js
|
|
1097
|
+
var require_headers = __commonJS({
|
|
1098
|
+
"node_modules/adm-zip/headers/index.js"(exports) {
|
|
1099
|
+
exports.EntryHeader = require_entryHeader();
|
|
1100
|
+
exports.MainHeader = require_mainHeader();
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
// node_modules/adm-zip/methods/deflater.js
|
|
1105
|
+
var require_deflater = __commonJS({
|
|
1106
|
+
"node_modules/adm-zip/methods/deflater.js"(exports, module) {
|
|
1107
|
+
module.exports = function(inbuf) {
|
|
1108
|
+
var zlib = __require("zlib");
|
|
1109
|
+
var opts = { chunkSize: (parseInt(inbuf.length / 1024) + 1) * 1024 };
|
|
1110
|
+
return {
|
|
1111
|
+
deflate: function() {
|
|
1112
|
+
return zlib.deflateRawSync(inbuf, opts);
|
|
1113
|
+
},
|
|
1114
|
+
deflateAsync: function(callback) {
|
|
1115
|
+
var tmp = zlib.createDeflateRaw(opts), parts = [], total = 0;
|
|
1116
|
+
tmp.on("data", function(data) {
|
|
1117
|
+
parts.push(data);
|
|
1118
|
+
total += data.length;
|
|
1119
|
+
});
|
|
1120
|
+
tmp.on("end", function() {
|
|
1121
|
+
var buf = Buffer.alloc(total), written = 0;
|
|
1122
|
+
buf.fill(0);
|
|
1123
|
+
for (var i = 0; i < parts.length; i++) {
|
|
1124
|
+
var part = parts[i];
|
|
1125
|
+
part.copy(buf, written);
|
|
1126
|
+
written += part.length;
|
|
1127
|
+
}
|
|
1128
|
+
callback && callback(buf);
|
|
1129
|
+
});
|
|
1130
|
+
tmp.end(inbuf);
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
// node_modules/adm-zip/methods/inflater.js
|
|
1138
|
+
var require_inflater = __commonJS({
|
|
1139
|
+
"node_modules/adm-zip/methods/inflater.js"(exports, module) {
|
|
1140
|
+
var version = +(process?.versions?.node ?? "").split(".")[0] || 0;
|
|
1141
|
+
module.exports = function(inbuf, expectedLength) {
|
|
1142
|
+
var zlib = __require("zlib");
|
|
1143
|
+
const option = version >= 15 && expectedLength > 0 ? { maxOutputLength: expectedLength } : {};
|
|
1144
|
+
return {
|
|
1145
|
+
inflate: function() {
|
|
1146
|
+
return zlib.inflateRawSync(inbuf, option);
|
|
1147
|
+
},
|
|
1148
|
+
inflateAsync: function(callback) {
|
|
1149
|
+
var tmp = zlib.createInflateRaw(option), parts = [], total = 0;
|
|
1150
|
+
tmp.on("data", function(data) {
|
|
1151
|
+
parts.push(data);
|
|
1152
|
+
total += data.length;
|
|
1153
|
+
});
|
|
1154
|
+
tmp.on("end", function() {
|
|
1155
|
+
var buf = Buffer.alloc(total), written = 0;
|
|
1156
|
+
buf.fill(0);
|
|
1157
|
+
for (var i = 0; i < parts.length; i++) {
|
|
1158
|
+
var part = parts[i];
|
|
1159
|
+
part.copy(buf, written);
|
|
1160
|
+
written += part.length;
|
|
1161
|
+
}
|
|
1162
|
+
callback && callback(buf);
|
|
1163
|
+
});
|
|
1164
|
+
tmp.end(inbuf);
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
// node_modules/adm-zip/methods/zipcrypto.js
|
|
1172
|
+
var require_zipcrypto = __commonJS({
|
|
1173
|
+
"node_modules/adm-zip/methods/zipcrypto.js"(exports, module) {
|
|
1174
|
+
"use strict";
|
|
1175
|
+
var { randomFillSync } = __require("crypto");
|
|
1176
|
+
var Errors = require_errors();
|
|
1177
|
+
var crctable = new Uint32Array(256).map((t, crc) => {
|
|
1178
|
+
for (let j = 0; j < 8; j++) {
|
|
1179
|
+
if (0 !== (crc & 1)) {
|
|
1180
|
+
crc = crc >>> 1 ^ 3988292384;
|
|
1181
|
+
} else {
|
|
1182
|
+
crc >>>= 1;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return crc >>> 0;
|
|
1186
|
+
});
|
|
1187
|
+
var uMul = (a, b) => Math.imul(a, b) >>> 0;
|
|
1188
|
+
var crc32update = (pCrc32, bval) => {
|
|
1189
|
+
return crctable[(pCrc32 ^ bval) & 255] ^ pCrc32 >>> 8;
|
|
1190
|
+
};
|
|
1191
|
+
var genSalt = () => {
|
|
1192
|
+
if ("function" === typeof randomFillSync) {
|
|
1193
|
+
return randomFillSync(Buffer.alloc(12));
|
|
1194
|
+
} else {
|
|
1195
|
+
return genSalt.node();
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
genSalt.node = () => {
|
|
1199
|
+
const salt = Buffer.alloc(12);
|
|
1200
|
+
const len = salt.length;
|
|
1201
|
+
for (let i = 0; i < len; i++) salt[i] = Math.random() * 256 & 255;
|
|
1202
|
+
return salt;
|
|
1203
|
+
};
|
|
1204
|
+
var config = {
|
|
1205
|
+
genSalt
|
|
1206
|
+
};
|
|
1207
|
+
function Initkeys(pw) {
|
|
1208
|
+
const pass = Buffer.isBuffer(pw) ? pw : Buffer.from(pw);
|
|
1209
|
+
this.keys = new Uint32Array([305419896, 591751049, 878082192]);
|
|
1210
|
+
for (let i = 0; i < pass.length; i++) {
|
|
1211
|
+
this.updateKeys(pass[i]);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
Initkeys.prototype.updateKeys = function(byteValue) {
|
|
1215
|
+
const keys = this.keys;
|
|
1216
|
+
keys[0] = crc32update(keys[0], byteValue);
|
|
1217
|
+
keys[1] += keys[0] & 255;
|
|
1218
|
+
keys[1] = uMul(keys[1], 134775813) + 1;
|
|
1219
|
+
keys[2] = crc32update(keys[2], keys[1] >>> 24);
|
|
1220
|
+
return byteValue;
|
|
1221
|
+
};
|
|
1222
|
+
Initkeys.prototype.next = function() {
|
|
1223
|
+
const k = (this.keys[2] | 2) >>> 0;
|
|
1224
|
+
return uMul(k, k ^ 1) >> 8 & 255;
|
|
1225
|
+
};
|
|
1226
|
+
function make_decrypter(pwd) {
|
|
1227
|
+
const keys = new Initkeys(pwd);
|
|
1228
|
+
return function(data) {
|
|
1229
|
+
const result = Buffer.alloc(data.length);
|
|
1230
|
+
let pos = 0;
|
|
1231
|
+
for (let c of data) {
|
|
1232
|
+
result[pos++] = keys.updateKeys(c ^ keys.next());
|
|
1233
|
+
}
|
|
1234
|
+
return result;
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
function make_encrypter(pwd) {
|
|
1238
|
+
const keys = new Initkeys(pwd);
|
|
1239
|
+
return function(data, result, pos = 0) {
|
|
1240
|
+
if (!result) result = Buffer.alloc(data.length);
|
|
1241
|
+
for (let c of data) {
|
|
1242
|
+
const k = keys.next();
|
|
1243
|
+
result[pos++] = c ^ k;
|
|
1244
|
+
keys.updateKeys(c);
|
|
1245
|
+
}
|
|
1246
|
+
return result;
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
function decrypt(data, header, pwd) {
|
|
1250
|
+
if (!data || !Buffer.isBuffer(data) || data.length < 12) {
|
|
1251
|
+
return Buffer.alloc(0);
|
|
1252
|
+
}
|
|
1253
|
+
const decrypter = make_decrypter(pwd);
|
|
1254
|
+
const salt = decrypter(data.slice(0, 12));
|
|
1255
|
+
const verifyByte = (header.flags & 8) === 8 ? header.timeHighByte : header.crc >>> 24;
|
|
1256
|
+
if (salt[11] !== verifyByte) {
|
|
1257
|
+
throw Errors.WRONG_PASSWORD();
|
|
1258
|
+
}
|
|
1259
|
+
return decrypter(data.slice(12));
|
|
1260
|
+
}
|
|
1261
|
+
function _salter(data) {
|
|
1262
|
+
if (Buffer.isBuffer(data) && data.length >= 12) {
|
|
1263
|
+
config.genSalt = function() {
|
|
1264
|
+
return data.slice(0, 12);
|
|
1265
|
+
};
|
|
1266
|
+
} else if (data === "node") {
|
|
1267
|
+
config.genSalt = genSalt.node;
|
|
1268
|
+
} else {
|
|
1269
|
+
config.genSalt = genSalt;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
function encrypt(data, header, pwd, oldlike = false) {
|
|
1273
|
+
if (data == null) data = Buffer.alloc(0);
|
|
1274
|
+
if (!Buffer.isBuffer(data)) data = Buffer.from(data.toString());
|
|
1275
|
+
const encrypter = make_encrypter(pwd);
|
|
1276
|
+
const salt = config.genSalt();
|
|
1277
|
+
salt[11] = header.crc >>> 24 & 255;
|
|
1278
|
+
if (oldlike) salt[10] = header.crc >>> 16 & 255;
|
|
1279
|
+
const result = Buffer.alloc(data.length + 12);
|
|
1280
|
+
encrypter(salt, result);
|
|
1281
|
+
return encrypter(data, result, 12);
|
|
1282
|
+
}
|
|
1283
|
+
module.exports = { decrypt, encrypt, _salter };
|
|
1284
|
+
}
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
// node_modules/adm-zip/methods/index.js
|
|
1288
|
+
var require_methods = __commonJS({
|
|
1289
|
+
"node_modules/adm-zip/methods/index.js"(exports) {
|
|
1290
|
+
exports.Deflater = require_deflater();
|
|
1291
|
+
exports.Inflater = require_inflater();
|
|
1292
|
+
exports.ZipCrypto = require_zipcrypto();
|
|
1293
|
+
}
|
|
1294
|
+
});
|
|
1295
|
+
|
|
1296
|
+
// node_modules/adm-zip/zipEntry.js
|
|
1297
|
+
var require_zipEntry = __commonJS({
|
|
1298
|
+
"node_modules/adm-zip/zipEntry.js"(exports, module) {
|
|
1299
|
+
var Utils = require_util();
|
|
1300
|
+
var Headers = require_headers();
|
|
1301
|
+
var Constants = Utils.Constants;
|
|
1302
|
+
var Methods = require_methods();
|
|
1303
|
+
module.exports = function(options, input) {
|
|
1304
|
+
var _centralHeader = new Headers.EntryHeader(), _entryName = Buffer.alloc(0), _comment = Buffer.alloc(0), _isDirectory = false, uncompressedData = null, _extra = Buffer.alloc(0), _extralocal = Buffer.alloc(0), _efs = true;
|
|
1305
|
+
const opts = options;
|
|
1306
|
+
const decoder = typeof opts.decoder === "object" ? opts.decoder : Utils.decoder;
|
|
1307
|
+
_efs = decoder.hasOwnProperty("efs") ? decoder.efs : false;
|
|
1308
|
+
function getCompressedDataFromZip() {
|
|
1309
|
+
if (!input || !(input instanceof Uint8Array)) {
|
|
1310
|
+
return Buffer.alloc(0);
|
|
1311
|
+
}
|
|
1312
|
+
_extralocal = _centralHeader.loadLocalHeaderFromBinary(input);
|
|
1313
|
+
return input.slice(_centralHeader.realDataOffset, _centralHeader.realDataOffset + _centralHeader.compressedSize);
|
|
1314
|
+
}
|
|
1315
|
+
function crc32OK(data) {
|
|
1316
|
+
const expectedCrc = _centralHeader.flags_desc || _centralHeader.localHeader.flags_desc ? _centralHeader.crc : _centralHeader.localHeader.crc;
|
|
1317
|
+
return Utils.crc32(data) === expectedCrc;
|
|
1318
|
+
}
|
|
1319
|
+
function decompress(async, callback, pass) {
|
|
1320
|
+
if (typeof callback === "undefined" && typeof async === "string") {
|
|
1321
|
+
pass = async;
|
|
1322
|
+
async = void 0;
|
|
1323
|
+
}
|
|
1324
|
+
if (_isDirectory) {
|
|
1325
|
+
if (async && callback) {
|
|
1326
|
+
callback(Buffer.alloc(0), Utils.Errors.DIRECTORY_CONTENT_ERROR());
|
|
1327
|
+
}
|
|
1328
|
+
return Buffer.alloc(0);
|
|
1329
|
+
}
|
|
1330
|
+
var compressedData = getCompressedDataFromZip();
|
|
1331
|
+
if (compressedData.length === 0) {
|
|
1332
|
+
if (async && callback) callback(compressedData);
|
|
1333
|
+
return compressedData;
|
|
1334
|
+
}
|
|
1335
|
+
if (_centralHeader.encrypted) {
|
|
1336
|
+
if ("string" !== typeof pass && !Buffer.isBuffer(pass)) {
|
|
1337
|
+
throw Utils.Errors.INVALID_PASS_PARAM();
|
|
1338
|
+
}
|
|
1339
|
+
compressedData = Methods.ZipCrypto.decrypt(compressedData, _centralHeader, pass);
|
|
1340
|
+
}
|
|
1341
|
+
var data;
|
|
1342
|
+
switch (_centralHeader.method) {
|
|
1343
|
+
case Utils.Constants.STORED:
|
|
1344
|
+
data = Buffer.alloc(compressedData.length);
|
|
1345
|
+
compressedData.copy(data);
|
|
1346
|
+
if (!crc32OK(data)) {
|
|
1347
|
+
if (async && callback) callback(data, Utils.Errors.BAD_CRC());
|
|
1348
|
+
throw Utils.Errors.BAD_CRC();
|
|
1349
|
+
} else {
|
|
1350
|
+
if (async && callback) callback(data);
|
|
1351
|
+
return data;
|
|
1352
|
+
}
|
|
1353
|
+
case Utils.Constants.DEFLATED:
|
|
1354
|
+
var inflater = new Methods.Inflater(compressedData, _centralHeader.size);
|
|
1355
|
+
if (!async) {
|
|
1356
|
+
data = inflater.inflate();
|
|
1357
|
+
if (!crc32OK(data)) {
|
|
1358
|
+
throw Utils.Errors.BAD_CRC(`"${decoder.decode(_entryName)}"`);
|
|
1359
|
+
}
|
|
1360
|
+
return data;
|
|
1361
|
+
} else {
|
|
1362
|
+
inflater.inflateAsync(function(result) {
|
|
1363
|
+
if (callback) {
|
|
1364
|
+
if (!crc32OK(result)) {
|
|
1365
|
+
callback(result, Utils.Errors.BAD_CRC());
|
|
1366
|
+
} else {
|
|
1367
|
+
callback(result);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
break;
|
|
1373
|
+
default:
|
|
1374
|
+
if (async && callback) callback(Buffer.alloc(0), Utils.Errors.UNKNOWN_METHOD());
|
|
1375
|
+
throw Utils.Errors.UNKNOWN_METHOD();
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
function compress(async, callback) {
|
|
1379
|
+
if ((!uncompressedData || !uncompressedData.length) && Buffer.isBuffer(input)) {
|
|
1380
|
+
if (async && callback) callback(getCompressedDataFromZip());
|
|
1381
|
+
return getCompressedDataFromZip();
|
|
1382
|
+
}
|
|
1383
|
+
if (uncompressedData.length && !_isDirectory) {
|
|
1384
|
+
var compressedData;
|
|
1385
|
+
switch (_centralHeader.method) {
|
|
1386
|
+
case Utils.Constants.STORED:
|
|
1387
|
+
_centralHeader.compressedSize = _centralHeader.size;
|
|
1388
|
+
compressedData = Buffer.alloc(uncompressedData.length);
|
|
1389
|
+
uncompressedData.copy(compressedData);
|
|
1390
|
+
if (async && callback) callback(compressedData);
|
|
1391
|
+
return compressedData;
|
|
1392
|
+
default:
|
|
1393
|
+
case Utils.Constants.DEFLATED:
|
|
1394
|
+
var deflater = new Methods.Deflater(uncompressedData);
|
|
1395
|
+
if (!async) {
|
|
1396
|
+
var deflated = deflater.deflate();
|
|
1397
|
+
_centralHeader.compressedSize = deflated.length;
|
|
1398
|
+
return deflated;
|
|
1399
|
+
} else {
|
|
1400
|
+
deflater.deflateAsync(function(data) {
|
|
1401
|
+
compressedData = Buffer.alloc(data.length);
|
|
1402
|
+
_centralHeader.compressedSize = data.length;
|
|
1403
|
+
data.copy(compressedData);
|
|
1404
|
+
callback && callback(compressedData);
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
deflater = null;
|
|
1408
|
+
break;
|
|
1409
|
+
}
|
|
1410
|
+
} else if (async && callback) {
|
|
1411
|
+
callback(Buffer.alloc(0));
|
|
1412
|
+
} else {
|
|
1413
|
+
return Buffer.alloc(0);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
function readUInt64LE(buffer, offset) {
|
|
1417
|
+
return Utils.readBigUInt64LE(buffer, offset);
|
|
1418
|
+
}
|
|
1419
|
+
function parseExtra(data) {
|
|
1420
|
+
try {
|
|
1421
|
+
var offset = 0;
|
|
1422
|
+
var signature, size, part;
|
|
1423
|
+
while (offset + 4 < data.length) {
|
|
1424
|
+
signature = data.readUInt16LE(offset);
|
|
1425
|
+
offset += 2;
|
|
1426
|
+
size = data.readUInt16LE(offset);
|
|
1427
|
+
offset += 2;
|
|
1428
|
+
part = data.slice(offset, offset + size);
|
|
1429
|
+
offset += size;
|
|
1430
|
+
if (Constants.ID_ZIP64 === signature) {
|
|
1431
|
+
parseZip64ExtendedInformation(part);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
throw Utils.Errors.EXTRA_FIELD_PARSE_ERROR();
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
function parseZip64ExtendedInformation(data) {
|
|
1439
|
+
var size, compressedSize, offset, diskNumStart;
|
|
1440
|
+
if (data.length >= Constants.EF_ZIP64_SCOMP) {
|
|
1441
|
+
size = readUInt64LE(data, Constants.EF_ZIP64_SUNCOMP);
|
|
1442
|
+
if (_centralHeader.size === Constants.EF_ZIP64_OR_32) {
|
|
1443
|
+
_centralHeader.size = size;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if (data.length >= Constants.EF_ZIP64_RHO) {
|
|
1447
|
+
compressedSize = readUInt64LE(data, Constants.EF_ZIP64_SCOMP);
|
|
1448
|
+
if (_centralHeader.compressedSize === Constants.EF_ZIP64_OR_32) {
|
|
1449
|
+
_centralHeader.compressedSize = compressedSize;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
if (data.length >= Constants.EF_ZIP64_DSN) {
|
|
1453
|
+
offset = readUInt64LE(data, Constants.EF_ZIP64_RHO);
|
|
1454
|
+
if (_centralHeader.offset === Constants.EF_ZIP64_OR_32) {
|
|
1455
|
+
_centralHeader.offset = offset;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
if (data.length >= Constants.EF_ZIP64_DSN + 4) {
|
|
1459
|
+
diskNumStart = data.readUInt32LE(Constants.EF_ZIP64_DSN);
|
|
1460
|
+
if (_centralHeader.diskNumStart === Constants.EF_ZIP64_OR_16) {
|
|
1461
|
+
_centralHeader.diskNumStart = diskNumStart;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return {
|
|
1466
|
+
get entryName() {
|
|
1467
|
+
return decoder.decode(_entryName);
|
|
1468
|
+
},
|
|
1469
|
+
get rawEntryName() {
|
|
1470
|
+
return _entryName;
|
|
1471
|
+
},
|
|
1472
|
+
set entryName(val) {
|
|
1473
|
+
_entryName = Utils.toBuffer(val, decoder.encode);
|
|
1474
|
+
var lastChar = _entryName[_entryName.length - 1];
|
|
1475
|
+
_isDirectory = lastChar === 47 || lastChar === 92;
|
|
1476
|
+
_centralHeader.fileNameLength = _entryName.length;
|
|
1477
|
+
},
|
|
1478
|
+
get efs() {
|
|
1479
|
+
if (typeof _efs === "function") {
|
|
1480
|
+
return _efs(this.entryName);
|
|
1481
|
+
} else {
|
|
1482
|
+
return _efs;
|
|
1483
|
+
}
|
|
1484
|
+
},
|
|
1485
|
+
get extra() {
|
|
1486
|
+
return _extra;
|
|
1487
|
+
},
|
|
1488
|
+
set extra(val) {
|
|
1489
|
+
_extra = val;
|
|
1490
|
+
_centralHeader.extraLength = val.length;
|
|
1491
|
+
parseExtra(val);
|
|
1492
|
+
},
|
|
1493
|
+
get comment() {
|
|
1494
|
+
return decoder.decode(_comment);
|
|
1495
|
+
},
|
|
1496
|
+
set comment(val) {
|
|
1497
|
+
_comment = Utils.toBuffer(val, decoder.encode);
|
|
1498
|
+
_centralHeader.commentLength = _comment.length;
|
|
1499
|
+
if (_comment.length > 65535) throw Utils.Errors.COMMENT_TOO_LONG();
|
|
1500
|
+
},
|
|
1501
|
+
get name() {
|
|
1502
|
+
const n = decoder.decode(_entryName);
|
|
1503
|
+
return _isDirectory ? n.replace(/[/\\]$/, "").split("/").pop() : n.split("/").pop();
|
|
1504
|
+
},
|
|
1505
|
+
get isDirectory() {
|
|
1506
|
+
return _isDirectory;
|
|
1507
|
+
},
|
|
1508
|
+
getCompressedData: function() {
|
|
1509
|
+
return compress(false, null);
|
|
1510
|
+
},
|
|
1511
|
+
getCompressedDataAsync: function(callback) {
|
|
1512
|
+
compress(true, callback);
|
|
1513
|
+
},
|
|
1514
|
+
setData: function(value) {
|
|
1515
|
+
uncompressedData = Utils.toBuffer(value, Utils.decoder.encode);
|
|
1516
|
+
if (!_isDirectory && uncompressedData.length) {
|
|
1517
|
+
_centralHeader.size = uncompressedData.length;
|
|
1518
|
+
_centralHeader.method = Utils.Constants.DEFLATED;
|
|
1519
|
+
_centralHeader.crc = Utils.crc32(value);
|
|
1520
|
+
_centralHeader.changed = true;
|
|
1521
|
+
} else {
|
|
1522
|
+
_centralHeader.method = Utils.Constants.STORED;
|
|
1523
|
+
}
|
|
1524
|
+
},
|
|
1525
|
+
getData: function(pass) {
|
|
1526
|
+
if (_centralHeader.changed) {
|
|
1527
|
+
return uncompressedData;
|
|
1528
|
+
} else {
|
|
1529
|
+
return decompress(false, null, pass);
|
|
1530
|
+
}
|
|
1531
|
+
},
|
|
1532
|
+
getDataAsync: function(callback, pass) {
|
|
1533
|
+
if (_centralHeader.changed) {
|
|
1534
|
+
callback(uncompressedData);
|
|
1535
|
+
} else {
|
|
1536
|
+
decompress(true, callback, pass);
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
set attr(attr) {
|
|
1540
|
+
_centralHeader.attr = attr;
|
|
1541
|
+
},
|
|
1542
|
+
get attr() {
|
|
1543
|
+
return _centralHeader.attr;
|
|
1544
|
+
},
|
|
1545
|
+
set header(data) {
|
|
1546
|
+
_centralHeader.loadFromBinary(data);
|
|
1547
|
+
},
|
|
1548
|
+
get header() {
|
|
1549
|
+
return _centralHeader;
|
|
1550
|
+
},
|
|
1551
|
+
packCentralHeader: function() {
|
|
1552
|
+
_centralHeader.flags_efs = this.efs;
|
|
1553
|
+
_centralHeader.extraLength = _extra.length;
|
|
1554
|
+
var header = _centralHeader.centralHeaderToBinary();
|
|
1555
|
+
var addpos = Utils.Constants.CENHDR;
|
|
1556
|
+
_entryName.copy(header, addpos);
|
|
1557
|
+
addpos += _entryName.length;
|
|
1558
|
+
_extra.copy(header, addpos);
|
|
1559
|
+
addpos += _centralHeader.extraLength;
|
|
1560
|
+
_comment.copy(header, addpos);
|
|
1561
|
+
return header;
|
|
1562
|
+
},
|
|
1563
|
+
packLocalHeader: function() {
|
|
1564
|
+
let addpos = 0;
|
|
1565
|
+
_centralHeader.flags_efs = this.efs;
|
|
1566
|
+
_centralHeader.extraLocalLength = _extralocal.length;
|
|
1567
|
+
const localHeaderBuf = _centralHeader.localHeaderToBinary();
|
|
1568
|
+
const localHeader = Buffer.alloc(localHeaderBuf.length + _entryName.length + _centralHeader.extraLocalLength);
|
|
1569
|
+
localHeaderBuf.copy(localHeader, addpos);
|
|
1570
|
+
addpos += localHeaderBuf.length;
|
|
1571
|
+
_entryName.copy(localHeader, addpos);
|
|
1572
|
+
addpos += _entryName.length;
|
|
1573
|
+
_extralocal.copy(localHeader, addpos);
|
|
1574
|
+
addpos += _extralocal.length;
|
|
1575
|
+
return localHeader;
|
|
1576
|
+
},
|
|
1577
|
+
toJSON: function() {
|
|
1578
|
+
const bytes = function(nr) {
|
|
1579
|
+
return "<" + (nr && nr.length + " bytes buffer" || "null") + ">";
|
|
1580
|
+
};
|
|
1581
|
+
return {
|
|
1582
|
+
entryName: this.entryName,
|
|
1583
|
+
name: this.name,
|
|
1584
|
+
comment: this.comment,
|
|
1585
|
+
isDirectory: this.isDirectory,
|
|
1586
|
+
header: _centralHeader.toJSON(),
|
|
1587
|
+
compressedData: bytes(input),
|
|
1588
|
+
data: bytes(uncompressedData)
|
|
1589
|
+
};
|
|
1590
|
+
},
|
|
1591
|
+
toString: function() {
|
|
1592
|
+
return JSON.stringify(this.toJSON(), null, " ");
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
|
|
1599
|
+
// node_modules/adm-zip/zipFile.js
|
|
1600
|
+
var require_zipFile = __commonJS({
|
|
1601
|
+
"node_modules/adm-zip/zipFile.js"(exports, module) {
|
|
1602
|
+
var ZipEntry = require_zipEntry();
|
|
1603
|
+
var Headers = require_headers();
|
|
1604
|
+
var Utils = require_util();
|
|
1605
|
+
module.exports = function(inBuffer, options) {
|
|
1606
|
+
var entryList = [], entryTable = /* @__PURE__ */ Object.create(null), _comment = Buffer.alloc(0), mainHeader = new Headers.MainHeader(), loadedEntries = false;
|
|
1607
|
+
var password = null;
|
|
1608
|
+
const temporary = /* @__PURE__ */ new Set();
|
|
1609
|
+
const opts = options;
|
|
1610
|
+
const { noSort, decoder } = opts;
|
|
1611
|
+
if (inBuffer) {
|
|
1612
|
+
readMainHeader(opts.readEntries);
|
|
1613
|
+
} else {
|
|
1614
|
+
loadedEntries = true;
|
|
1615
|
+
}
|
|
1616
|
+
function makeTemporaryFolders() {
|
|
1617
|
+
const foldersList = /* @__PURE__ */ new Set();
|
|
1618
|
+
for (const elem of Object.keys(entryTable)) {
|
|
1619
|
+
const elements = elem.split("/");
|
|
1620
|
+
elements.pop();
|
|
1621
|
+
if (!elements.length) continue;
|
|
1622
|
+
for (let i = 0; i < elements.length; i++) {
|
|
1623
|
+
const sub = elements.slice(0, i + 1).join("/") + "/";
|
|
1624
|
+
foldersList.add(sub);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
for (const elem of foldersList) {
|
|
1628
|
+
if (!(elem in entryTable)) {
|
|
1629
|
+
const tempfolder = new ZipEntry(opts);
|
|
1630
|
+
tempfolder.entryName = elem;
|
|
1631
|
+
tempfolder.attr = 16;
|
|
1632
|
+
tempfolder.temporary = true;
|
|
1633
|
+
entryList.push(tempfolder);
|
|
1634
|
+
entryTable[tempfolder.entryName] = tempfolder;
|
|
1635
|
+
temporary.add(tempfolder);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
function readEntries() {
|
|
1640
|
+
loadedEntries = true;
|
|
1641
|
+
entryTable = /* @__PURE__ */ Object.create(null);
|
|
1642
|
+
if (mainHeader.diskEntries > (inBuffer.length - mainHeader.offset) / Utils.Constants.CENHDR) {
|
|
1643
|
+
throw Utils.Errors.DISK_ENTRY_TOO_LARGE();
|
|
1644
|
+
}
|
|
1645
|
+
entryList = new Array(mainHeader.diskEntries);
|
|
1646
|
+
var index = mainHeader.offset;
|
|
1647
|
+
for (var i = 0; i < entryList.length; i++) {
|
|
1648
|
+
var tmp = index, entry = new ZipEntry(opts, inBuffer);
|
|
1649
|
+
entry.header = inBuffer.slice(tmp, tmp += Utils.Constants.CENHDR);
|
|
1650
|
+
entry.entryName = inBuffer.slice(tmp, tmp += entry.header.fileNameLength);
|
|
1651
|
+
if (entry.header.extraLength) {
|
|
1652
|
+
entry.extra = inBuffer.slice(tmp, tmp += entry.header.extraLength);
|
|
1653
|
+
}
|
|
1654
|
+
if (entry.header.commentLength) entry.comment = inBuffer.slice(tmp, tmp + entry.header.commentLength);
|
|
1655
|
+
index += entry.header.centralHeaderSize;
|
|
1656
|
+
entryList[i] = entry;
|
|
1657
|
+
entryTable[entry.entryName] = entry;
|
|
1658
|
+
}
|
|
1659
|
+
temporary.clear();
|
|
1660
|
+
makeTemporaryFolders();
|
|
1661
|
+
}
|
|
1662
|
+
function readMainHeader(readNow) {
|
|
1663
|
+
var i = inBuffer.length - Utils.Constants.ENDHDR, max = Math.max(0, i - 65535), n = max, endStart = inBuffer.length, endOffset = -1, commentEnd = 0;
|
|
1664
|
+
const trailingSpace = typeof opts.trailingSpace === "boolean" ? opts.trailingSpace : false;
|
|
1665
|
+
if (trailingSpace) max = 0;
|
|
1666
|
+
for (i; i >= n; i--) {
|
|
1667
|
+
if (inBuffer[i] !== 80) continue;
|
|
1668
|
+
if (inBuffer.readUInt32LE(i) === Utils.Constants.ENDSIG) {
|
|
1669
|
+
endOffset = i;
|
|
1670
|
+
commentEnd = i;
|
|
1671
|
+
endStart = i + Utils.Constants.ENDHDR;
|
|
1672
|
+
n = i - Utils.Constants.END64HDR;
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1675
|
+
if (inBuffer.readUInt32LE(i) === Utils.Constants.END64SIG) {
|
|
1676
|
+
n = max;
|
|
1677
|
+
continue;
|
|
1678
|
+
}
|
|
1679
|
+
if (inBuffer.readUInt32LE(i) === Utils.Constants.ZIP64SIG) {
|
|
1680
|
+
endOffset = i;
|
|
1681
|
+
endStart = i + Utils.readBigUInt64LE(inBuffer, i + Utils.Constants.ZIP64SIZE) + Utils.Constants.ZIP64LEAD;
|
|
1682
|
+
break;
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (endOffset == -1) throw Utils.Errors.INVALID_FORMAT();
|
|
1686
|
+
mainHeader.loadFromBinary(inBuffer.slice(endOffset, endStart));
|
|
1687
|
+
if (mainHeader.commentLength) {
|
|
1688
|
+
_comment = inBuffer.slice(commentEnd + Utils.Constants.ENDHDR);
|
|
1689
|
+
}
|
|
1690
|
+
if (readNow) readEntries();
|
|
1691
|
+
}
|
|
1692
|
+
function sortEntries() {
|
|
1693
|
+
if (entryList.length > 1 && !noSort) {
|
|
1694
|
+
entryList = entryList.map((entry) => ({ entry, key: entry.entryName.toLowerCase() })).sort((a, b) => a.key.localeCompare(b.key)).map((pair) => pair.entry);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
return {
|
|
1698
|
+
/**
|
|
1699
|
+
* Returns an array of ZipEntry objects existent in the current opened archive
|
|
1700
|
+
* @return Array
|
|
1701
|
+
*/
|
|
1702
|
+
get entries() {
|
|
1703
|
+
if (!loadedEntries) {
|
|
1704
|
+
readEntries();
|
|
1705
|
+
}
|
|
1706
|
+
return entryList.filter((e) => !temporary.has(e));
|
|
1707
|
+
},
|
|
1708
|
+
/**
|
|
1709
|
+
* Archive comment
|
|
1710
|
+
* @return {String}
|
|
1711
|
+
*/
|
|
1712
|
+
get comment() {
|
|
1713
|
+
return decoder.decode(_comment);
|
|
1714
|
+
},
|
|
1715
|
+
set comment(val) {
|
|
1716
|
+
_comment = Utils.toBuffer(val, decoder.encode);
|
|
1717
|
+
mainHeader.commentLength = _comment.length;
|
|
1718
|
+
},
|
|
1719
|
+
getEntryCount: function() {
|
|
1720
|
+
if (!loadedEntries) {
|
|
1721
|
+
return mainHeader.diskEntries;
|
|
1722
|
+
}
|
|
1723
|
+
return entryList.length;
|
|
1724
|
+
},
|
|
1725
|
+
forEach: function(callback) {
|
|
1726
|
+
this.entries.forEach(callback);
|
|
1727
|
+
},
|
|
1728
|
+
/**
|
|
1729
|
+
* Returns a reference to the entry with the given name or null if entry is inexistent
|
|
1730
|
+
*
|
|
1731
|
+
* @param entryName
|
|
1732
|
+
* @return ZipEntry
|
|
1733
|
+
*/
|
|
1734
|
+
getEntry: function(entryName) {
|
|
1735
|
+
if (!loadedEntries) {
|
|
1736
|
+
readEntries();
|
|
1737
|
+
}
|
|
1738
|
+
return entryTable[entryName] || null;
|
|
1739
|
+
},
|
|
1740
|
+
/**
|
|
1741
|
+
* Adds the given entry to the entry list
|
|
1742
|
+
*
|
|
1743
|
+
* @param entry
|
|
1744
|
+
*/
|
|
1745
|
+
setEntry: function(entry) {
|
|
1746
|
+
if (!loadedEntries) {
|
|
1747
|
+
readEntries();
|
|
1748
|
+
}
|
|
1749
|
+
entryList.push(entry);
|
|
1750
|
+
entryTable[entry.entryName] = entry;
|
|
1751
|
+
mainHeader.totalEntries = entryList.length;
|
|
1752
|
+
},
|
|
1753
|
+
/**
|
|
1754
|
+
* Removes the file with the given name from the entry list.
|
|
1755
|
+
*
|
|
1756
|
+
* If the entry is a directory, then all nested files and directories will be removed
|
|
1757
|
+
* @param entryName
|
|
1758
|
+
* @returns {void}
|
|
1759
|
+
*/
|
|
1760
|
+
deleteFile: function(entryName, withsubfolders = true) {
|
|
1761
|
+
if (!loadedEntries) {
|
|
1762
|
+
readEntries();
|
|
1763
|
+
}
|
|
1764
|
+
const entry = entryTable[entryName];
|
|
1765
|
+
const list = this.getEntryChildren(entry, withsubfolders).map((child) => child.entryName);
|
|
1766
|
+
list.forEach(this.deleteEntry);
|
|
1767
|
+
},
|
|
1768
|
+
/**
|
|
1769
|
+
* Removes the entry with the given name from the entry list.
|
|
1770
|
+
*
|
|
1771
|
+
* @param {string} entryName
|
|
1772
|
+
* @returns {void}
|
|
1773
|
+
*/
|
|
1774
|
+
deleteEntry: function(entryName) {
|
|
1775
|
+
if (!loadedEntries) {
|
|
1776
|
+
readEntries();
|
|
1777
|
+
}
|
|
1778
|
+
const entry = entryTable[entryName];
|
|
1779
|
+
const index = entryList.indexOf(entry);
|
|
1780
|
+
if (index >= 0) {
|
|
1781
|
+
entryList.splice(index, 1);
|
|
1782
|
+
delete entryTable[entryName];
|
|
1783
|
+
mainHeader.totalEntries = entryList.length;
|
|
1784
|
+
}
|
|
1785
|
+
},
|
|
1786
|
+
/**
|
|
1787
|
+
* Iterates and returns all nested files and directories of the given entry
|
|
1788
|
+
*
|
|
1789
|
+
* @param entry
|
|
1790
|
+
* @return Array
|
|
1791
|
+
*/
|
|
1792
|
+
getEntryChildren: function(entry, subfolders = true) {
|
|
1793
|
+
if (!loadedEntries) {
|
|
1794
|
+
readEntries();
|
|
1795
|
+
}
|
|
1796
|
+
if (typeof entry === "object") {
|
|
1797
|
+
if (entry.isDirectory && subfolders) {
|
|
1798
|
+
const list = [];
|
|
1799
|
+
const name = entry.entryName;
|
|
1800
|
+
for (const zipEntry of entryList) {
|
|
1801
|
+
if (zipEntry.entryName.startsWith(name)) {
|
|
1802
|
+
list.push(zipEntry);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
return list;
|
|
1806
|
+
} else {
|
|
1807
|
+
return [entry];
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
return [];
|
|
1811
|
+
},
|
|
1812
|
+
/**
|
|
1813
|
+
* How many child elements entry has
|
|
1814
|
+
*
|
|
1815
|
+
* @param {ZipEntry} entry
|
|
1816
|
+
* @return {integer}
|
|
1817
|
+
*/
|
|
1818
|
+
getChildCount: function(entry) {
|
|
1819
|
+
if (entry && entry.isDirectory) {
|
|
1820
|
+
const list = this.getEntryChildren(entry);
|
|
1821
|
+
return list.includes(entry) ? list.length - 1 : list.length;
|
|
1822
|
+
}
|
|
1823
|
+
return 0;
|
|
1824
|
+
},
|
|
1825
|
+
/**
|
|
1826
|
+
* Returns the zip file
|
|
1827
|
+
*
|
|
1828
|
+
* @return Buffer
|
|
1829
|
+
*/
|
|
1830
|
+
compressToBuffer: function() {
|
|
1831
|
+
if (!loadedEntries) {
|
|
1832
|
+
readEntries();
|
|
1833
|
+
}
|
|
1834
|
+
sortEntries();
|
|
1835
|
+
const dataBlock = [];
|
|
1836
|
+
const headerBlocks = [];
|
|
1837
|
+
let totalSize = 0;
|
|
1838
|
+
let dindex = 0;
|
|
1839
|
+
mainHeader.size = 0;
|
|
1840
|
+
mainHeader.offset = 0;
|
|
1841
|
+
let totalEntries = 0;
|
|
1842
|
+
for (const entry of this.entries) {
|
|
1843
|
+
const compressedData = entry.getCompressedData();
|
|
1844
|
+
entry.header.offset = dindex;
|
|
1845
|
+
const localHeader = entry.packLocalHeader();
|
|
1846
|
+
const dataLength = localHeader.length + compressedData.length;
|
|
1847
|
+
dindex += dataLength;
|
|
1848
|
+
dataBlock.push(localHeader);
|
|
1849
|
+
dataBlock.push(compressedData);
|
|
1850
|
+
const centralHeader = entry.packCentralHeader();
|
|
1851
|
+
headerBlocks.push(centralHeader);
|
|
1852
|
+
mainHeader.size += centralHeader.length;
|
|
1853
|
+
totalSize += dataLength + centralHeader.length;
|
|
1854
|
+
totalEntries++;
|
|
1855
|
+
}
|
|
1856
|
+
totalSize += mainHeader.mainHeaderSize;
|
|
1857
|
+
mainHeader.offset = dindex;
|
|
1858
|
+
mainHeader.totalEntries = totalEntries;
|
|
1859
|
+
dindex = 0;
|
|
1860
|
+
const outBuffer = Buffer.alloc(totalSize);
|
|
1861
|
+
for (const content of dataBlock) {
|
|
1862
|
+
content.copy(outBuffer, dindex);
|
|
1863
|
+
dindex += content.length;
|
|
1864
|
+
}
|
|
1865
|
+
for (const content of headerBlocks) {
|
|
1866
|
+
content.copy(outBuffer, dindex);
|
|
1867
|
+
dindex += content.length;
|
|
1868
|
+
}
|
|
1869
|
+
const mh = mainHeader.toBinary();
|
|
1870
|
+
if (_comment) {
|
|
1871
|
+
_comment.copy(mh, mh.length - _comment.length);
|
|
1872
|
+
}
|
|
1873
|
+
mh.copy(outBuffer, dindex);
|
|
1874
|
+
inBuffer = outBuffer;
|
|
1875
|
+
loadedEntries = false;
|
|
1876
|
+
return outBuffer;
|
|
1877
|
+
},
|
|
1878
|
+
toAsyncBuffer: function(onSuccess, onFail, onItemStart, onItemEnd) {
|
|
1879
|
+
try {
|
|
1880
|
+
if (!loadedEntries) {
|
|
1881
|
+
readEntries();
|
|
1882
|
+
}
|
|
1883
|
+
sortEntries();
|
|
1884
|
+
const dataBlock = [];
|
|
1885
|
+
const centralHeaders = [];
|
|
1886
|
+
let totalSize = 0;
|
|
1887
|
+
let dindex = 0;
|
|
1888
|
+
let totalEntries = 0;
|
|
1889
|
+
mainHeader.size = 0;
|
|
1890
|
+
mainHeader.offset = 0;
|
|
1891
|
+
const compress2Buffer = function(entryLists) {
|
|
1892
|
+
if (entryLists.length > 0) {
|
|
1893
|
+
const entry = entryLists.shift();
|
|
1894
|
+
const name = entry.entryName + entry.extra.toString();
|
|
1895
|
+
if (onItemStart) onItemStart(name);
|
|
1896
|
+
entry.getCompressedDataAsync(function(compressedData) {
|
|
1897
|
+
if (onItemEnd) onItemEnd(name);
|
|
1898
|
+
entry.header.offset = dindex;
|
|
1899
|
+
const localHeader = entry.packLocalHeader();
|
|
1900
|
+
const dataLength = localHeader.length + compressedData.length;
|
|
1901
|
+
dindex += dataLength;
|
|
1902
|
+
dataBlock.push(localHeader);
|
|
1903
|
+
dataBlock.push(compressedData);
|
|
1904
|
+
const centalHeader = entry.packCentralHeader();
|
|
1905
|
+
centralHeaders.push(centalHeader);
|
|
1906
|
+
mainHeader.size += centalHeader.length;
|
|
1907
|
+
totalSize += dataLength + centalHeader.length;
|
|
1908
|
+
totalEntries++;
|
|
1909
|
+
compress2Buffer(entryLists);
|
|
1910
|
+
});
|
|
1911
|
+
} else {
|
|
1912
|
+
totalSize += mainHeader.mainHeaderSize;
|
|
1913
|
+
mainHeader.offset = dindex;
|
|
1914
|
+
mainHeader.totalEntries = totalEntries;
|
|
1915
|
+
dindex = 0;
|
|
1916
|
+
const outBuffer = Buffer.alloc(totalSize);
|
|
1917
|
+
dataBlock.forEach(function(content) {
|
|
1918
|
+
content.copy(outBuffer, dindex);
|
|
1919
|
+
dindex += content.length;
|
|
1920
|
+
});
|
|
1921
|
+
centralHeaders.forEach(function(content) {
|
|
1922
|
+
content.copy(outBuffer, dindex);
|
|
1923
|
+
dindex += content.length;
|
|
1924
|
+
});
|
|
1925
|
+
const mh = mainHeader.toBinary();
|
|
1926
|
+
if (_comment) {
|
|
1927
|
+
_comment.copy(mh, mh.length - _comment.length);
|
|
1928
|
+
}
|
|
1929
|
+
mh.copy(outBuffer, dindex);
|
|
1930
|
+
inBuffer = outBuffer;
|
|
1931
|
+
loadedEntries = false;
|
|
1932
|
+
onSuccess(outBuffer);
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
compress2Buffer(Array.from(this.entries));
|
|
1936
|
+
} catch (e) {
|
|
1937
|
+
onFail(e);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
});
|
|
1944
|
+
|
|
1945
|
+
// node_modules/adm-zip/adm-zip.js
|
|
1946
|
+
var require_adm_zip = __commonJS({
|
|
1947
|
+
"node_modules/adm-zip/adm-zip.js"(exports, module) {
|
|
1948
|
+
var Utils = require_util();
|
|
1949
|
+
var pth = __require("path");
|
|
1950
|
+
var ZipEntry = require_zipEntry();
|
|
1951
|
+
var ZipFile = require_zipFile();
|
|
1952
|
+
var get_Bool = (...val) => Utils.findLast(val, (c) => typeof c === "boolean");
|
|
1953
|
+
var get_Str = (...val) => Utils.findLast(val, (c) => typeof c === "string");
|
|
1954
|
+
var get_Fun = (...val) => Utils.findLast(val, (c) => typeof c === "function");
|
|
1955
|
+
var defaultOptions = {
|
|
1956
|
+
// option "noSort" : if true it disables files sorting
|
|
1957
|
+
noSort: false,
|
|
1958
|
+
// read entries during load (initial loading may be slower)
|
|
1959
|
+
readEntries: false,
|
|
1960
|
+
// default method is none
|
|
1961
|
+
method: Utils.Constants.NONE,
|
|
1962
|
+
// file system
|
|
1963
|
+
fs: null
|
|
1964
|
+
};
|
|
1965
|
+
module.exports = function(input, options) {
|
|
1966
|
+
let inBuffer = null;
|
|
1967
|
+
const opts = Object.assign(/* @__PURE__ */ Object.create(null), defaultOptions);
|
|
1968
|
+
if (input && "object" === typeof input) {
|
|
1969
|
+
if (!(input instanceof Uint8Array)) {
|
|
1970
|
+
Object.assign(opts, input);
|
|
1971
|
+
input = opts.input ? opts.input : void 0;
|
|
1972
|
+
if (opts.input) delete opts.input;
|
|
1973
|
+
}
|
|
1974
|
+
if (Buffer.isBuffer(input)) {
|
|
1975
|
+
inBuffer = input;
|
|
1976
|
+
opts.method = Utils.Constants.BUFFER;
|
|
1977
|
+
input = void 0;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
Object.assign(opts, options);
|
|
1981
|
+
const filetools = new Utils(opts);
|
|
1982
|
+
const applyDirAttributes = (dirEntries) => {
|
|
1983
|
+
dirEntries.filter((d) => d.attr).sort((a, b) => b.path.length - a.path.length).forEach((d) => filetools.fs.chmodSync(d.path, d.attr));
|
|
1984
|
+
};
|
|
1985
|
+
if (typeof opts.decoder !== "object" || typeof opts.decoder.encode !== "function" || typeof opts.decoder.decode !== "function") {
|
|
1986
|
+
opts.decoder = Utils.decoder;
|
|
1987
|
+
}
|
|
1988
|
+
if (input && "string" === typeof input) {
|
|
1989
|
+
if (filetools.fs.existsSync(input)) {
|
|
1990
|
+
opts.method = Utils.Constants.FILE;
|
|
1991
|
+
opts.filename = input;
|
|
1992
|
+
inBuffer = filetools.fs.readFileSync(input);
|
|
1993
|
+
} else {
|
|
1994
|
+
throw Utils.Errors.INVALID_FILENAME();
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
const _zip = new ZipFile(inBuffer, opts);
|
|
1998
|
+
const { canonical, sanitize, zipnamefix } = Utils;
|
|
1999
|
+
function getEntry(entry) {
|
|
2000
|
+
if (entry && _zip) {
|
|
2001
|
+
var item;
|
|
2002
|
+
if (typeof entry === "string") item = _zip.getEntry(pth.posix.normalize(entry));
|
|
2003
|
+
if (typeof entry === "object" && typeof entry.entryName !== "undefined" && typeof entry.header !== "undefined") item = _zip.getEntry(entry.entryName);
|
|
2004
|
+
if (item) {
|
|
2005
|
+
return item;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
return null;
|
|
2009
|
+
}
|
|
2010
|
+
function fixPath(zipPath) {
|
|
2011
|
+
const { join, normalize, sep } = pth.posix;
|
|
2012
|
+
return join(pth.isAbsolute(zipPath) ? "/" : ".", normalize(sep + zipPath.split("\\").join(sep) + sep));
|
|
2013
|
+
}
|
|
2014
|
+
function filenameFilter(filterfn) {
|
|
2015
|
+
if (filterfn instanceof RegExp) {
|
|
2016
|
+
return /* @__PURE__ */ (function(rx) {
|
|
2017
|
+
return function(filename) {
|
|
2018
|
+
return rx.test(filename);
|
|
2019
|
+
};
|
|
2020
|
+
})(filterfn);
|
|
2021
|
+
} else if ("function" !== typeof filterfn) {
|
|
2022
|
+
return () => true;
|
|
2023
|
+
}
|
|
2024
|
+
return filterfn;
|
|
2025
|
+
}
|
|
2026
|
+
const relativePath = (local, entry) => {
|
|
2027
|
+
let lastChar = entry.slice(-1);
|
|
2028
|
+
lastChar = lastChar === filetools.sep ? filetools.sep : "";
|
|
2029
|
+
return pth.relative(local, entry) + lastChar;
|
|
2030
|
+
};
|
|
2031
|
+
return {
|
|
2032
|
+
/**
|
|
2033
|
+
* Extracts the given entry from the archive and returns the content as a Buffer object
|
|
2034
|
+
* @param {ZipEntry|string} entry ZipEntry object or String with the full path of the entry
|
|
2035
|
+
* @param {Buffer|string} [pass] - password
|
|
2036
|
+
* @return Buffer or Null in case of error
|
|
2037
|
+
*/
|
|
2038
|
+
readFile: function(entry, pass) {
|
|
2039
|
+
var item = getEntry(entry);
|
|
2040
|
+
return item && item.getData(pass) || null;
|
|
2041
|
+
},
|
|
2042
|
+
/**
|
|
2043
|
+
* Returns how many child elements has on entry (directories) on files it is always 0
|
|
2044
|
+
* @param {ZipEntry|string} entry ZipEntry object or String with the full path of the entry
|
|
2045
|
+
* @returns {integer}
|
|
2046
|
+
*/
|
|
2047
|
+
childCount: function(entry) {
|
|
2048
|
+
const item = getEntry(entry);
|
|
2049
|
+
if (item) {
|
|
2050
|
+
return _zip.getChildCount(item);
|
|
2051
|
+
}
|
|
2052
|
+
},
|
|
2053
|
+
/**
|
|
2054
|
+
* Asynchronous readFile
|
|
2055
|
+
* @param {ZipEntry|string} entry ZipEntry object or String with the full path of the entry
|
|
2056
|
+
* @param {callback} callback
|
|
2057
|
+
*
|
|
2058
|
+
* @return Buffer or Null in case of error
|
|
2059
|
+
*/
|
|
2060
|
+
readFileAsync: function(entry, callback) {
|
|
2061
|
+
var item = getEntry(entry);
|
|
2062
|
+
if (item) {
|
|
2063
|
+
item.getDataAsync(callback);
|
|
2064
|
+
} else {
|
|
2065
|
+
callback(null, "getEntry failed for:" + entry);
|
|
2066
|
+
}
|
|
2067
|
+
},
|
|
2068
|
+
/**
|
|
2069
|
+
* Extracts the given entry from the archive and returns the content as plain text in the given encoding
|
|
2070
|
+
* @param {ZipEntry|string} entry - ZipEntry object or String with the full path of the entry
|
|
2071
|
+
* @param {string} encoding - Optional. If no encoding is specified utf8 is used
|
|
2072
|
+
*
|
|
2073
|
+
* @return String
|
|
2074
|
+
*/
|
|
2075
|
+
readAsText: function(entry, encoding) {
|
|
2076
|
+
var item = getEntry(entry);
|
|
2077
|
+
if (item) {
|
|
2078
|
+
var data = item.getData();
|
|
2079
|
+
if (data && data.length) {
|
|
2080
|
+
return data.toString(encoding || "utf8");
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
return "";
|
|
2084
|
+
},
|
|
2085
|
+
/**
|
|
2086
|
+
* Asynchronous readAsText
|
|
2087
|
+
* @param {ZipEntry|string} entry ZipEntry object or String with the full path of the entry
|
|
2088
|
+
* @param {callback} callback
|
|
2089
|
+
* @param {string} [encoding] - Optional. If no encoding is specified utf8 is used
|
|
2090
|
+
*
|
|
2091
|
+
* @return String
|
|
2092
|
+
*/
|
|
2093
|
+
readAsTextAsync: function(entry, callback, encoding) {
|
|
2094
|
+
var item = getEntry(entry);
|
|
2095
|
+
if (item) {
|
|
2096
|
+
item.getDataAsync(function(data, err) {
|
|
2097
|
+
if (err) {
|
|
2098
|
+
callback(data, err);
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
if (data && data.length) {
|
|
2102
|
+
callback(data.toString(encoding || "utf8"));
|
|
2103
|
+
} else {
|
|
2104
|
+
callback("");
|
|
2105
|
+
}
|
|
2106
|
+
});
|
|
2107
|
+
} else {
|
|
2108
|
+
callback("");
|
|
2109
|
+
}
|
|
2110
|
+
},
|
|
2111
|
+
/**
|
|
2112
|
+
* Remove the entry from the file or the entry and all it's nested directories and files if the given entry is a directory
|
|
2113
|
+
*
|
|
2114
|
+
* @param {ZipEntry|string} entry
|
|
2115
|
+
* @param {boolean} withsubfolders
|
|
2116
|
+
* @returns {void}
|
|
2117
|
+
*/
|
|
2118
|
+
deleteFile: function(entry, withsubfolders = true) {
|
|
2119
|
+
var item = getEntry(entry);
|
|
2120
|
+
if (item) {
|
|
2121
|
+
_zip.deleteFile(item.entryName, withsubfolders);
|
|
2122
|
+
}
|
|
2123
|
+
},
|
|
2124
|
+
/**
|
|
2125
|
+
* Remove the entry from the file or directory without affecting any nested entries
|
|
2126
|
+
*
|
|
2127
|
+
* @param {ZipEntry|string} entry
|
|
2128
|
+
* @returns {void}
|
|
2129
|
+
*/
|
|
2130
|
+
deleteEntry: function(entry) {
|
|
2131
|
+
var item = getEntry(entry);
|
|
2132
|
+
if (item) {
|
|
2133
|
+
_zip.deleteEntry(item.entryName);
|
|
2134
|
+
}
|
|
2135
|
+
},
|
|
2136
|
+
/**
|
|
2137
|
+
* Adds a comment to the zip. The zip must be rewritten after adding the comment.
|
|
2138
|
+
*
|
|
2139
|
+
* @param {string} comment
|
|
2140
|
+
*/
|
|
2141
|
+
addZipComment: function(comment) {
|
|
2142
|
+
_zip.comment = comment;
|
|
2143
|
+
},
|
|
2144
|
+
/**
|
|
2145
|
+
* Returns the zip comment
|
|
2146
|
+
*
|
|
2147
|
+
* @return String
|
|
2148
|
+
*/
|
|
2149
|
+
getZipComment: function() {
|
|
2150
|
+
return _zip.comment || "";
|
|
2151
|
+
},
|
|
2152
|
+
/**
|
|
2153
|
+
* Adds a comment to a specified zipEntry. The zip must be rewritten after adding the comment
|
|
2154
|
+
* The comment cannot exceed 65535 characters in length
|
|
2155
|
+
*
|
|
2156
|
+
* @param {ZipEntry} entry
|
|
2157
|
+
* @param {string} comment
|
|
2158
|
+
*/
|
|
2159
|
+
addZipEntryComment: function(entry, comment) {
|
|
2160
|
+
var item = getEntry(entry);
|
|
2161
|
+
if (item) {
|
|
2162
|
+
item.comment = comment;
|
|
2163
|
+
}
|
|
2164
|
+
},
|
|
2165
|
+
/**
|
|
2166
|
+
* Returns the comment of the specified entry
|
|
2167
|
+
*
|
|
2168
|
+
* @param {ZipEntry} entry
|
|
2169
|
+
* @return String
|
|
2170
|
+
*/
|
|
2171
|
+
getZipEntryComment: function(entry) {
|
|
2172
|
+
var item = getEntry(entry);
|
|
2173
|
+
if (item) {
|
|
2174
|
+
return item.comment || "";
|
|
2175
|
+
}
|
|
2176
|
+
return "";
|
|
2177
|
+
},
|
|
2178
|
+
/**
|
|
2179
|
+
* Updates the content of an existing entry inside the archive. The zip must be rewritten after updating the content
|
|
2180
|
+
*
|
|
2181
|
+
* @param {ZipEntry} entry
|
|
2182
|
+
* @param {Buffer} content
|
|
2183
|
+
*/
|
|
2184
|
+
updateFile: function(entry, content) {
|
|
2185
|
+
var item = getEntry(entry);
|
|
2186
|
+
if (item) {
|
|
2187
|
+
item.setData(content);
|
|
2188
|
+
}
|
|
2189
|
+
},
|
|
2190
|
+
/**
|
|
2191
|
+
* Adds a file from the disk to the archive
|
|
2192
|
+
*
|
|
2193
|
+
* @param {string} localPath File to add to zip
|
|
2194
|
+
* @param {string} [zipPath] Optional path inside the zip
|
|
2195
|
+
* @param {string} [zipName] Optional name for the file
|
|
2196
|
+
* @param {string} [comment] Optional file comment
|
|
2197
|
+
*/
|
|
2198
|
+
addLocalFile: function(localPath, zipPath, zipName, comment) {
|
|
2199
|
+
if (filetools.fs.existsSync(localPath)) {
|
|
2200
|
+
zipPath = zipPath ? fixPath(zipPath) : "";
|
|
2201
|
+
const p = pth.win32.basename(pth.win32.normalize(localPath));
|
|
2202
|
+
zipPath += zipName ? zipName : p;
|
|
2203
|
+
const _attr = filetools.fs.statSync(localPath);
|
|
2204
|
+
const data = _attr.isFile() ? filetools.fs.readFileSync(localPath) : Buffer.alloc(0);
|
|
2205
|
+
if (_attr.isDirectory()) zipPath += filetools.sep;
|
|
2206
|
+
this.addFile(zipPath, data, comment, _attr);
|
|
2207
|
+
} else {
|
|
2208
|
+
throw Utils.Errors.FILE_NOT_FOUND(localPath);
|
|
2209
|
+
}
|
|
2210
|
+
},
|
|
2211
|
+
/**
|
|
2212
|
+
* Callback for showing if everything was done.
|
|
2213
|
+
*
|
|
2214
|
+
* @callback doneCallback
|
|
2215
|
+
* @param {Error} err - Error object
|
|
2216
|
+
* @param {boolean} done - was request fully completed
|
|
2217
|
+
*/
|
|
2218
|
+
/**
|
|
2219
|
+
* Adds a file from the disk to the archive
|
|
2220
|
+
*
|
|
2221
|
+
* @param {(object|string)} options - options object, if it is string it us used as localPath.
|
|
2222
|
+
* @param {string} options.localPath - Local path to the file.
|
|
2223
|
+
* @param {string} [options.comment] - Optional file comment.
|
|
2224
|
+
* @param {string} [options.zipPath] - Optional path inside the zip
|
|
2225
|
+
* @param {string} [options.zipName] - Optional name for the file
|
|
2226
|
+
* @param {doneCallback} callback - The callback that handles the response.
|
|
2227
|
+
*/
|
|
2228
|
+
addLocalFileAsync: function(options2, callback) {
|
|
2229
|
+
options2 = typeof options2 === "object" ? options2 : { localPath: options2 };
|
|
2230
|
+
const localPath = pth.resolve(options2.localPath);
|
|
2231
|
+
const { comment } = options2;
|
|
2232
|
+
let { zipPath, zipName } = options2;
|
|
2233
|
+
const self = this;
|
|
2234
|
+
filetools.fs.stat(localPath, function(err, stats) {
|
|
2235
|
+
if (err) return callback(err, false);
|
|
2236
|
+
zipPath = zipPath ? fixPath(zipPath) : "";
|
|
2237
|
+
const p = pth.win32.basename(pth.win32.normalize(localPath));
|
|
2238
|
+
zipPath += zipName ? zipName : p;
|
|
2239
|
+
if (stats.isFile()) {
|
|
2240
|
+
filetools.fs.readFile(localPath, function(err2, data) {
|
|
2241
|
+
if (err2) return callback(err2, false);
|
|
2242
|
+
self.addFile(zipPath, data, comment, stats);
|
|
2243
|
+
return setImmediate(callback, void 0, true);
|
|
2244
|
+
});
|
|
2245
|
+
} else if (stats.isDirectory()) {
|
|
2246
|
+
zipPath += filetools.sep;
|
|
2247
|
+
self.addFile(zipPath, Buffer.alloc(0), comment, stats);
|
|
2248
|
+
return setImmediate(callback, void 0, true);
|
|
2249
|
+
}
|
|
2250
|
+
});
|
|
2251
|
+
},
|
|
2252
|
+
/**
|
|
2253
|
+
* Adds a local directory and all its nested files and directories to the archive
|
|
2254
|
+
*
|
|
2255
|
+
* @param {string} localPath - local path to the folder
|
|
2256
|
+
* @param {string} [zipPath] - optional path inside zip
|
|
2257
|
+
* @param {(RegExp|function)} [filter] - optional RegExp or Function if files match will be included.
|
|
2258
|
+
*/
|
|
2259
|
+
addLocalFolder: function(localPath, zipPath, filter) {
|
|
2260
|
+
filter = filenameFilter(filter);
|
|
2261
|
+
zipPath = zipPath ? fixPath(zipPath) : "";
|
|
2262
|
+
localPath = pth.normalize(localPath);
|
|
2263
|
+
if (filetools.fs.existsSync(localPath)) {
|
|
2264
|
+
const items = filetools.findFiles(localPath);
|
|
2265
|
+
const self = this;
|
|
2266
|
+
if (items.length) {
|
|
2267
|
+
for (const filepath of items) {
|
|
2268
|
+
const p = pth.join(zipPath, relativePath(localPath, filepath));
|
|
2269
|
+
if (filter(p)) {
|
|
2270
|
+
self.addLocalFile(filepath, pth.dirname(p));
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
} else {
|
|
2275
|
+
throw Utils.Errors.FILE_NOT_FOUND(localPath);
|
|
2276
|
+
}
|
|
2277
|
+
},
|
|
2278
|
+
/**
|
|
2279
|
+
* Asynchronous addLocalFolder
|
|
2280
|
+
* @param {string} localPath
|
|
2281
|
+
* @param {callback} callback
|
|
2282
|
+
* @param {string} [zipPath] optional path inside zip
|
|
2283
|
+
* @param {RegExp|function} [filter] optional RegExp or Function if files match will
|
|
2284
|
+
* be included.
|
|
2285
|
+
*/
|
|
2286
|
+
addLocalFolderAsync: function(localPath, callback, zipPath, filter) {
|
|
2287
|
+
filter = filenameFilter(filter);
|
|
2288
|
+
zipPath = zipPath ? fixPath(zipPath) : "";
|
|
2289
|
+
localPath = pth.normalize(localPath);
|
|
2290
|
+
var self = this;
|
|
2291
|
+
filetools.fs.open(localPath, "r", function(err) {
|
|
2292
|
+
if (err && err.code === "ENOENT") {
|
|
2293
|
+
callback(void 0, Utils.Errors.FILE_NOT_FOUND(localPath));
|
|
2294
|
+
} else if (err) {
|
|
2295
|
+
callback(void 0, err);
|
|
2296
|
+
} else {
|
|
2297
|
+
var items = filetools.findFiles(localPath);
|
|
2298
|
+
var i = -1;
|
|
2299
|
+
var next = function() {
|
|
2300
|
+
i += 1;
|
|
2301
|
+
if (i < items.length) {
|
|
2302
|
+
var filepath = items[i];
|
|
2303
|
+
var p = relativePath(localPath, filepath).split("\\").join("/");
|
|
2304
|
+
p = p.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\x20-\x7E]/g, "");
|
|
2305
|
+
if (filter(p)) {
|
|
2306
|
+
filetools.fs.stat(filepath, function(er0, stats) {
|
|
2307
|
+
if (er0) callback(void 0, er0);
|
|
2308
|
+
if (stats.isFile()) {
|
|
2309
|
+
filetools.fs.readFile(filepath, function(er1, data) {
|
|
2310
|
+
if (er1) {
|
|
2311
|
+
callback(void 0, er1);
|
|
2312
|
+
} else {
|
|
2313
|
+
self.addFile(zipPath + p, data, "", stats);
|
|
2314
|
+
next();
|
|
2315
|
+
}
|
|
2316
|
+
});
|
|
2317
|
+
} else {
|
|
2318
|
+
self.addFile(zipPath + p + "/", Buffer.alloc(0), "", stats);
|
|
2319
|
+
next();
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
} else {
|
|
2323
|
+
process.nextTick(() => {
|
|
2324
|
+
next();
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
} else {
|
|
2328
|
+
callback(true, void 0);
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
next();
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
},
|
|
2335
|
+
/**
|
|
2336
|
+
* Adds a local directory and all its nested files and directories to the archive
|
|
2337
|
+
*
|
|
2338
|
+
* @param {object | string} options - options object, if it is string it us used as localPath.
|
|
2339
|
+
* @param {string} options.localPath - Local path to the folder.
|
|
2340
|
+
* @param {string} [options.zipPath] - optional path inside zip.
|
|
2341
|
+
* @param {RegExp|function} [options.filter] - optional RegExp or Function if files match will be included.
|
|
2342
|
+
* @param {function|string} [options.namefix] - optional function to help fix filename
|
|
2343
|
+
* @param {doneCallback} callback - The callback that handles the response.
|
|
2344
|
+
*
|
|
2345
|
+
*/
|
|
2346
|
+
addLocalFolderAsync2: function(options2, callback) {
|
|
2347
|
+
const self = this;
|
|
2348
|
+
options2 = typeof options2 === "object" ? options2 : { localPath: options2 };
|
|
2349
|
+
const localPath = pth.resolve(fixPath(options2.localPath));
|
|
2350
|
+
let { zipPath, filter, namefix } = options2;
|
|
2351
|
+
if (filter instanceof RegExp) {
|
|
2352
|
+
filter = /* @__PURE__ */ (function(rx) {
|
|
2353
|
+
return function(filename) {
|
|
2354
|
+
return rx.test(filename);
|
|
2355
|
+
};
|
|
2356
|
+
})(filter);
|
|
2357
|
+
} else if ("function" !== typeof filter) {
|
|
2358
|
+
filter = function() {
|
|
2359
|
+
return true;
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
zipPath = zipPath ? fixPath(zipPath) : "";
|
|
2363
|
+
if (namefix === "latin1") {
|
|
2364
|
+
namefix = (str) => str.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\x20-\x7E]/g, "");
|
|
2365
|
+
}
|
|
2366
|
+
if (typeof namefix !== "function") namefix = (str) => str;
|
|
2367
|
+
const relPathFix = (entry) => pth.join(zipPath, namefix(relativePath(localPath, entry)));
|
|
2368
|
+
const fileNameFix = (entry) => pth.win32.basename(pth.win32.normalize(namefix(entry)));
|
|
2369
|
+
filetools.fs.open(localPath, "r", function(err) {
|
|
2370
|
+
if (err && err.code === "ENOENT") {
|
|
2371
|
+
callback(void 0, Utils.Errors.FILE_NOT_FOUND(localPath));
|
|
2372
|
+
} else if (err) {
|
|
2373
|
+
callback(void 0, err);
|
|
2374
|
+
} else {
|
|
2375
|
+
filetools.findFilesAsync(localPath, function(err2, fileEntries) {
|
|
2376
|
+
if (err2) return callback(err2);
|
|
2377
|
+
fileEntries = fileEntries.filter((dir) => filter(relPathFix(dir)));
|
|
2378
|
+
if (!fileEntries.length) callback(void 0, false);
|
|
2379
|
+
setImmediate(
|
|
2380
|
+
fileEntries.reverse().reduce(function(next, entry) {
|
|
2381
|
+
return function(err3, done) {
|
|
2382
|
+
if (err3 || done === false) return setImmediate(next, err3, false);
|
|
2383
|
+
self.addLocalFileAsync(
|
|
2384
|
+
{
|
|
2385
|
+
localPath: entry,
|
|
2386
|
+
zipPath: pth.dirname(relPathFix(entry)),
|
|
2387
|
+
zipName: fileNameFix(entry)
|
|
2388
|
+
},
|
|
2389
|
+
next
|
|
2390
|
+
);
|
|
2391
|
+
};
|
|
2392
|
+
}, callback)
|
|
2393
|
+
);
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2396
|
+
});
|
|
2397
|
+
},
|
|
2398
|
+
/**
|
|
2399
|
+
* Adds a local directory and all its nested files and directories to the archive
|
|
2400
|
+
*
|
|
2401
|
+
* @param {string} localPath - path where files will be extracted
|
|
2402
|
+
* @param {object} props - optional properties
|
|
2403
|
+
* @param {string} [props.zipPath] - optional path inside zip
|
|
2404
|
+
* @param {RegExp|function} [props.filter] - optional RegExp or Function if files match will be included.
|
|
2405
|
+
* @param {function|string} [props.namefix] - optional function to help fix filename
|
|
2406
|
+
*/
|
|
2407
|
+
addLocalFolderPromise: function(localPath, props) {
|
|
2408
|
+
return new Promise((resolve, reject) => {
|
|
2409
|
+
this.addLocalFolderAsync2(Object.assign({ localPath }, props), (err, done) => {
|
|
2410
|
+
if (err) reject(err);
|
|
2411
|
+
if (done) resolve(this);
|
|
2412
|
+
});
|
|
2413
|
+
});
|
|
2414
|
+
},
|
|
2415
|
+
/**
|
|
2416
|
+
* Allows you to create a entry (file or directory) in the zip file.
|
|
2417
|
+
* If you want to create a directory the entryName must end in / and a null buffer should be provided.
|
|
2418
|
+
* Comment and attributes are optional
|
|
2419
|
+
*
|
|
2420
|
+
* @param {string} entryName
|
|
2421
|
+
* @param {Buffer | string} content - file content as buffer or utf8 coded string
|
|
2422
|
+
* @param {string} [comment] - file comment
|
|
2423
|
+
* @param {number | object} [attr] - number as unix file permissions, object as filesystem Stats object
|
|
2424
|
+
*/
|
|
2425
|
+
addFile: function(entryName, content, comment, attr) {
|
|
2426
|
+
entryName = zipnamefix(entryName);
|
|
2427
|
+
let entry = getEntry(entryName);
|
|
2428
|
+
const update = entry != null;
|
|
2429
|
+
if (!update) {
|
|
2430
|
+
entry = new ZipEntry(opts);
|
|
2431
|
+
entry.entryName = entryName;
|
|
2432
|
+
}
|
|
2433
|
+
entry.comment = comment || "";
|
|
2434
|
+
const isStat = "object" === typeof attr && attr instanceof filetools.fs.Stats;
|
|
2435
|
+
if (isStat) {
|
|
2436
|
+
entry.header.time = attr.mtime;
|
|
2437
|
+
}
|
|
2438
|
+
var fileattr = entry.isDirectory ? 16 : 0;
|
|
2439
|
+
let unix = entry.isDirectory ? 16384 : 32768;
|
|
2440
|
+
if (isStat) {
|
|
2441
|
+
unix |= 4095 & attr.mode;
|
|
2442
|
+
} else if ("number" === typeof attr) {
|
|
2443
|
+
unix |= 4095 & attr;
|
|
2444
|
+
} else {
|
|
2445
|
+
unix |= entry.isDirectory ? 493 : 420;
|
|
2446
|
+
}
|
|
2447
|
+
fileattr = (fileattr | unix << 16) >>> 0;
|
|
2448
|
+
entry.attr = fileattr;
|
|
2449
|
+
entry.setData(content);
|
|
2450
|
+
if (!update) _zip.setEntry(entry);
|
|
2451
|
+
return entry;
|
|
2452
|
+
},
|
|
2453
|
+
/**
|
|
2454
|
+
* Returns an array of ZipEntry objects representing the files and folders inside the archive
|
|
2455
|
+
*
|
|
2456
|
+
* @param {string} [password]
|
|
2457
|
+
* @returns Array
|
|
2458
|
+
*/
|
|
2459
|
+
getEntries: function(password) {
|
|
2460
|
+
_zip.password = password;
|
|
2461
|
+
return _zip ? _zip.entries : [];
|
|
2462
|
+
},
|
|
2463
|
+
/**
|
|
2464
|
+
* Returns a ZipEntry object representing the file or folder specified by ``name``.
|
|
2465
|
+
*
|
|
2466
|
+
* @param {string} name
|
|
2467
|
+
* @return ZipEntry
|
|
2468
|
+
*/
|
|
2469
|
+
getEntry: function(name) {
|
|
2470
|
+
return getEntry(name);
|
|
2471
|
+
},
|
|
2472
|
+
getEntryCount: function() {
|
|
2473
|
+
return _zip.getEntryCount();
|
|
2474
|
+
},
|
|
2475
|
+
forEach: function(callback) {
|
|
2476
|
+
return _zip.forEach(callback);
|
|
2477
|
+
},
|
|
2478
|
+
/**
|
|
2479
|
+
* Extracts the given entry to the given targetPath
|
|
2480
|
+
* If the entry is a directory inside the archive, the entire directory and it's subdirectories will be extracted
|
|
2481
|
+
*
|
|
2482
|
+
* @param {string|ZipEntry} entry - ZipEntry object or String with the full path of the entry
|
|
2483
|
+
* @param {string} targetPath - Target folder where to write the file
|
|
2484
|
+
* @param {boolean} [maintainEntryPath=true] - If maintainEntryPath is true and the entry is inside a folder, the entry folder will be created in targetPath as well. Default is TRUE
|
|
2485
|
+
* @param {boolean} [overwrite=false] - If the file already exists at the target path, the file will be overwriten if this is true.
|
|
2486
|
+
* @param {boolean} [keepOriginalPermission=false] - The file will be set as the permission from the entry if this is true.
|
|
2487
|
+
* @param {string} [outFileName] - String If set will override the filename of the extracted file (Only works if the entry is a file)
|
|
2488
|
+
*
|
|
2489
|
+
* @return Boolean
|
|
2490
|
+
*/
|
|
2491
|
+
extractEntryTo: function(entry, targetPath, maintainEntryPath, overwrite, keepOriginalPermission, outFileName) {
|
|
2492
|
+
overwrite = get_Bool(false, overwrite);
|
|
2493
|
+
keepOriginalPermission = get_Bool(false, keepOriginalPermission);
|
|
2494
|
+
maintainEntryPath = get_Bool(true, maintainEntryPath);
|
|
2495
|
+
outFileName = get_Str(keepOriginalPermission, outFileName);
|
|
2496
|
+
var item = getEntry(entry);
|
|
2497
|
+
if (!item) {
|
|
2498
|
+
throw Utils.Errors.NO_ENTRY();
|
|
2499
|
+
}
|
|
2500
|
+
var entryName = canonical(item.entryName);
|
|
2501
|
+
var target = sanitize(targetPath, outFileName && !item.isDirectory ? canonical(outFileName) : maintainEntryPath ? entryName : pth.basename(entryName));
|
|
2502
|
+
if (item.isDirectory) {
|
|
2503
|
+
var children = _zip.getEntryChildren(item);
|
|
2504
|
+
children.forEach(function(child) {
|
|
2505
|
+
if (child.isDirectory) return;
|
|
2506
|
+
var content2 = child.getData();
|
|
2507
|
+
if (!content2) {
|
|
2508
|
+
throw Utils.Errors.CANT_EXTRACT_FILE();
|
|
2509
|
+
}
|
|
2510
|
+
var name = canonical(maintainEntryPath ? child.entryName : child.entryName.substring(item.entryName.length));
|
|
2511
|
+
var childName = sanitize(targetPath, name);
|
|
2512
|
+
const fileAttr2 = keepOriginalPermission ? child.header.fileAttr : void 0;
|
|
2513
|
+
filetools.writeFileTo(childName, content2, overwrite, fileAttr2);
|
|
2514
|
+
});
|
|
2515
|
+
return true;
|
|
2516
|
+
}
|
|
2517
|
+
var content = item.getData(_zip.password);
|
|
2518
|
+
if (!content) throw Utils.Errors.CANT_EXTRACT_FILE();
|
|
2519
|
+
if (filetools.fs.existsSync(target) && !overwrite) {
|
|
2520
|
+
throw Utils.Errors.CANT_OVERRIDE();
|
|
2521
|
+
}
|
|
2522
|
+
const fileAttr = keepOriginalPermission ? entry.header.fileAttr : void 0;
|
|
2523
|
+
filetools.writeFileTo(target, content, overwrite, fileAttr);
|
|
2524
|
+
return true;
|
|
2525
|
+
},
|
|
2526
|
+
/**
|
|
2527
|
+
* Test the archive
|
|
2528
|
+
* @param {string} [pass]
|
|
2529
|
+
*/
|
|
2530
|
+
test: function(pass) {
|
|
2531
|
+
if (!_zip) {
|
|
2532
|
+
return false;
|
|
2533
|
+
}
|
|
2534
|
+
for (var entry of _zip.entries) {
|
|
2535
|
+
try {
|
|
2536
|
+
if (entry.isDirectory) {
|
|
2537
|
+
continue;
|
|
2538
|
+
}
|
|
2539
|
+
var content = entry.getData(pass);
|
|
2540
|
+
if (!content) {
|
|
2541
|
+
return false;
|
|
2542
|
+
}
|
|
2543
|
+
} catch (err) {
|
|
2544
|
+
return false;
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
return true;
|
|
2548
|
+
},
|
|
2549
|
+
/**
|
|
2550
|
+
* Extracts the entire archive to the given location
|
|
2551
|
+
*
|
|
2552
|
+
* @param {string} targetPath Target location
|
|
2553
|
+
* @param {boolean} [overwrite=false] If the file already exists at the target path, the file will be overwriten if this is true.
|
|
2554
|
+
* Default is FALSE
|
|
2555
|
+
* @param {boolean} [keepOriginalPermission=false] The file will be set as the permission from the entry if this is true.
|
|
2556
|
+
* Default is FALSE
|
|
2557
|
+
* @param {string|Buffer} [pass] password
|
|
2558
|
+
*/
|
|
2559
|
+
extractAllTo: function(targetPath, overwrite, keepOriginalPermission, pass) {
|
|
2560
|
+
keepOriginalPermission = get_Bool(false, keepOriginalPermission);
|
|
2561
|
+
pass = get_Str(keepOriginalPermission, pass);
|
|
2562
|
+
overwrite = get_Bool(false, overwrite);
|
|
2563
|
+
if (!_zip) throw Utils.Errors.NO_ZIP();
|
|
2564
|
+
const dirEntries = [];
|
|
2565
|
+
_zip.entries.forEach(function(entry) {
|
|
2566
|
+
var entryName = sanitize(targetPath, canonical(entry.entryName));
|
|
2567
|
+
if (entry.isDirectory) {
|
|
2568
|
+
filetools.makeDir(entryName);
|
|
2569
|
+
if (keepOriginalPermission) dirEntries.push({ path: entryName, attr: entry.header.fileAttr });
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
var content = entry.getData(pass);
|
|
2573
|
+
if (!content) {
|
|
2574
|
+
throw Utils.Errors.CANT_EXTRACT_FILE();
|
|
2575
|
+
}
|
|
2576
|
+
const fileAttr = keepOriginalPermission ? entry.header.fileAttr : void 0;
|
|
2577
|
+
filetools.writeFileTo(entryName, content, overwrite, fileAttr);
|
|
2578
|
+
try {
|
|
2579
|
+
filetools.fs.utimesSync(entryName, entry.header.time, entry.header.time);
|
|
2580
|
+
} catch (err) {
|
|
2581
|
+
}
|
|
2582
|
+
});
|
|
2583
|
+
applyDirAttributes(dirEntries);
|
|
2584
|
+
},
|
|
2585
|
+
/**
|
|
2586
|
+
* Asynchronous extractAllTo
|
|
2587
|
+
*
|
|
2588
|
+
* @param {string} targetPath Target location
|
|
2589
|
+
* @param {boolean} [overwrite=false] If the file already exists at the target path, the file will be overwriten if this is true.
|
|
2590
|
+
* Default is FALSE
|
|
2591
|
+
* @param {boolean} [keepOriginalPermission=false] The file will be set as the permission from the entry if this is true.
|
|
2592
|
+
* Default is FALSE
|
|
2593
|
+
* @param {function} callback The callback will be executed when all entries are extracted successfully or any error is thrown.
|
|
2594
|
+
*/
|
|
2595
|
+
extractAllToAsync: function(targetPath, overwrite, keepOriginalPermission, callback) {
|
|
2596
|
+
callback = get_Fun(overwrite, keepOriginalPermission, callback);
|
|
2597
|
+
keepOriginalPermission = get_Bool(false, keepOriginalPermission);
|
|
2598
|
+
overwrite = get_Bool(false, overwrite);
|
|
2599
|
+
if (!callback) {
|
|
2600
|
+
return new Promise((resolve, reject) => {
|
|
2601
|
+
this.extractAllToAsync(targetPath, overwrite, keepOriginalPermission, function(err) {
|
|
2602
|
+
if (err) {
|
|
2603
|
+
reject(err);
|
|
2604
|
+
} else {
|
|
2605
|
+
resolve(this);
|
|
2606
|
+
}
|
|
2607
|
+
});
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
if (!_zip) {
|
|
2611
|
+
callback(Utils.Errors.NO_ZIP());
|
|
2612
|
+
return;
|
|
2613
|
+
}
|
|
2614
|
+
targetPath = pth.resolve(targetPath);
|
|
2615
|
+
const getPath = (entry) => sanitize(targetPath, pth.normalize(canonical(entry.entryName)));
|
|
2616
|
+
const getError = (msg, file) => new Error(msg + ': "' + file + '"');
|
|
2617
|
+
const dirEntries = [];
|
|
2618
|
+
const fileEntries = [];
|
|
2619
|
+
_zip.entries.forEach((e) => {
|
|
2620
|
+
if (e.isDirectory) {
|
|
2621
|
+
dirEntries.push(e);
|
|
2622
|
+
} else {
|
|
2623
|
+
fileEntries.push(e);
|
|
2624
|
+
}
|
|
2625
|
+
});
|
|
2626
|
+
const deferredDirAttr = [];
|
|
2627
|
+
for (const entry of dirEntries) {
|
|
2628
|
+
const dirPath = getPath(entry);
|
|
2629
|
+
const dirAttr = keepOriginalPermission ? entry.header.fileAttr : void 0;
|
|
2630
|
+
try {
|
|
2631
|
+
filetools.makeDir(dirPath);
|
|
2632
|
+
} catch (er) {
|
|
2633
|
+
callback(getError("Unable to create folder", dirPath));
|
|
2634
|
+
continue;
|
|
2635
|
+
}
|
|
2636
|
+
if (dirAttr) deferredDirAttr.push({ path: dirPath, attr: dirAttr });
|
|
2637
|
+
try {
|
|
2638
|
+
filetools.fs.utimesSync(dirPath, entry.header.time, entry.header.time);
|
|
2639
|
+
} catch (er) {
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
const done = (err) => {
|
|
2643
|
+
if (!err) {
|
|
2644
|
+
try {
|
|
2645
|
+
applyDirAttributes(deferredDirAttr);
|
|
2646
|
+
} catch (er) {
|
|
2647
|
+
return callback(getError("Unable to set folder permissions", er.path || ""));
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
callback(err);
|
|
2651
|
+
};
|
|
2652
|
+
fileEntries.reverse().reduce(function(next, entry) {
|
|
2653
|
+
return function(err) {
|
|
2654
|
+
if (err) {
|
|
2655
|
+
next(err);
|
|
2656
|
+
} else {
|
|
2657
|
+
const entryName = pth.normalize(canonical(entry.entryName));
|
|
2658
|
+
const filePath = sanitize(targetPath, entryName);
|
|
2659
|
+
entry.getDataAsync(function(content, err_1) {
|
|
2660
|
+
if (err_1) {
|
|
2661
|
+
next(err_1);
|
|
2662
|
+
} else if (!content) {
|
|
2663
|
+
next(Utils.Errors.CANT_EXTRACT_FILE());
|
|
2664
|
+
} else {
|
|
2665
|
+
const fileAttr = keepOriginalPermission ? entry.header.fileAttr : void 0;
|
|
2666
|
+
filetools.writeFileToAsync(filePath, content, overwrite, fileAttr, function(succ) {
|
|
2667
|
+
if (!succ) {
|
|
2668
|
+
return next(getError("Unable to write file", filePath));
|
|
2669
|
+
}
|
|
2670
|
+
filetools.fs.utimes(filePath, entry.header.time, entry.header.time, function() {
|
|
2671
|
+
next();
|
|
2672
|
+
});
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
};
|
|
2678
|
+
}, done)();
|
|
2679
|
+
},
|
|
2680
|
+
/**
|
|
2681
|
+
* Writes the newly created zip file to disk at the specified location or if a zip was opened and no ``targetFileName`` is provided, it will overwrite the opened zip
|
|
2682
|
+
*
|
|
2683
|
+
* @param {string} targetFileName
|
|
2684
|
+
* @param {function} callback
|
|
2685
|
+
*/
|
|
2686
|
+
writeZip: function(targetFileName, callback) {
|
|
2687
|
+
if (arguments.length === 1) {
|
|
2688
|
+
if (typeof targetFileName === "function") {
|
|
2689
|
+
callback = targetFileName;
|
|
2690
|
+
targetFileName = "";
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
if (!targetFileName && opts.filename) {
|
|
2694
|
+
targetFileName = opts.filename;
|
|
2695
|
+
}
|
|
2696
|
+
if (!targetFileName) return;
|
|
2697
|
+
var zipData = _zip.compressToBuffer();
|
|
2698
|
+
if (zipData) {
|
|
2699
|
+
var ok = filetools.writeFileTo(targetFileName, zipData, true);
|
|
2700
|
+
if (typeof callback === "function") callback(!ok ? new Error("failed") : null, "");
|
|
2701
|
+
}
|
|
2702
|
+
},
|
|
2703
|
+
/**
|
|
2704
|
+
*
|
|
2705
|
+
* @param {string} targetFileName
|
|
2706
|
+
* @param {object} [props]
|
|
2707
|
+
* @param {boolean} [props.overwrite=true] If the file already exists at the target path, the file will be overwriten if this is true.
|
|
2708
|
+
* @param {boolean} [props.perm] The file will be set as the permission from the entry if this is true.
|
|
2709
|
+
|
|
2710
|
+
* @returns {Promise<void>}
|
|
2711
|
+
*/
|
|
2712
|
+
writeZipPromise: function(targetFileName, props) {
|
|
2713
|
+
const { overwrite, perm } = Object.assign({ overwrite: true }, props);
|
|
2714
|
+
return new Promise((resolve, reject) => {
|
|
2715
|
+
if (!targetFileName && opts.filename) targetFileName = opts.filename;
|
|
2716
|
+
if (!targetFileName) reject("ADM-ZIP: ZIP File Name Missing");
|
|
2717
|
+
this.toBufferPromise().then((zipData) => {
|
|
2718
|
+
const ret = (done) => done ? resolve(done) : reject("ADM-ZIP: Wasn't able to write zip file");
|
|
2719
|
+
filetools.writeFileToAsync(targetFileName, zipData, overwrite, perm, ret);
|
|
2720
|
+
}, reject);
|
|
2721
|
+
});
|
|
2722
|
+
},
|
|
2723
|
+
/**
|
|
2724
|
+
* @returns {Promise<Buffer>} A promise to the Buffer.
|
|
2725
|
+
*/
|
|
2726
|
+
toBufferPromise: function() {
|
|
2727
|
+
return new Promise((resolve, reject) => {
|
|
2728
|
+
_zip.toAsyncBuffer(resolve, reject);
|
|
2729
|
+
});
|
|
2730
|
+
},
|
|
2731
|
+
/**
|
|
2732
|
+
* Returns the content of the entire zip file as a Buffer object
|
|
2733
|
+
*
|
|
2734
|
+
* @prop {function} [onSuccess]
|
|
2735
|
+
* @prop {function} [onFail]
|
|
2736
|
+
* @prop {function} [onItemStart]
|
|
2737
|
+
* @prop {function} [onItemEnd]
|
|
2738
|
+
* @returns {Buffer}
|
|
2739
|
+
*/
|
|
2740
|
+
toBuffer: function(onSuccess, onFail, onItemStart, onItemEnd) {
|
|
2741
|
+
if (typeof onSuccess === "function") {
|
|
2742
|
+
_zip.toAsyncBuffer(onSuccess, onFail, onItemStart, onItemEnd);
|
|
2743
|
+
return null;
|
|
2744
|
+
}
|
|
2745
|
+
return _zip.compressToBuffer();
|
|
2746
|
+
}
|
|
2747
|
+
};
|
|
2748
|
+
};
|
|
2749
|
+
}
|
|
2750
|
+
});
|
|
2751
|
+
|
|
1
2752
|
// src/index.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2753
|
+
import fs9 from "node:fs";
|
|
2754
|
+
import path11 from "node:path";
|
|
4
2755
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5
2756
|
import os4 from "node:os";
|
|
6
2757
|
|
|
@@ -101,12 +2852,11 @@ var ActiveSkills = class {
|
|
|
101
2852
|
};
|
|
102
2853
|
|
|
103
2854
|
// src/updater.ts
|
|
2855
|
+
var import_adm_zip = __toESM(require_adm_zip(), 1);
|
|
104
2856
|
import fs3 from "node:fs/promises";
|
|
105
2857
|
import fsSync from "node:fs";
|
|
106
2858
|
import path3 from "node:path";
|
|
107
2859
|
import os2 from "node:os";
|
|
108
|
-
import { execFile } from "node:child_process";
|
|
109
|
-
import { promisify } from "node:util";
|
|
110
2860
|
import { randomUUID, createHash } from "node:crypto";
|
|
111
2861
|
|
|
112
2862
|
// src/skill-version.ts
|
|
@@ -139,14 +2889,27 @@ function parseSkillVersion(content) {
|
|
|
139
2889
|
}
|
|
140
2890
|
|
|
141
2891
|
// src/updater.ts
|
|
142
|
-
var execFileAsync = promisify(execFile);
|
|
143
2892
|
var ATTEMPT_COOLDOWN_MS = 30 * 60 * 1e3;
|
|
144
2893
|
function skillIdentityHash(code, version) {
|
|
145
2894
|
return createHash("sha256").update(`${code} ${code} ${version}`).digest("hex");
|
|
146
2895
|
}
|
|
147
2896
|
async function systemUnzip(zipPath, destDir) {
|
|
148
2897
|
await fs3.mkdir(destDir, { recursive: true });
|
|
149
|
-
|
|
2898
|
+
const destRoot = path3.resolve(destDir);
|
|
2899
|
+
const zip = new import_adm_zip.default(zipPath);
|
|
2900
|
+
for (const entry of zip.getEntries()) {
|
|
2901
|
+
const normalizedName = entry.entryName.replace(/\\/g, "/");
|
|
2902
|
+
const outPath = path3.resolve(destRoot, normalizedName);
|
|
2903
|
+
if (outPath !== destRoot && !outPath.startsWith(destRoot + path3.sep)) {
|
|
2904
|
+
throw new Error(`ZIP \u5305\u542B\u975E\u6CD5\u8DEF\u5F84: ${entry.entryName}`);
|
|
2905
|
+
}
|
|
2906
|
+
if (entry.isDirectory) {
|
|
2907
|
+
await fs3.mkdir(outPath, { recursive: true });
|
|
2908
|
+
continue;
|
|
2909
|
+
}
|
|
2910
|
+
await fs3.mkdir(path3.dirname(outPath), { recursive: true });
|
|
2911
|
+
await fs3.writeFile(outPath, entry.getData());
|
|
2912
|
+
}
|
|
150
2913
|
}
|
|
151
2914
|
var SkillUpdater = class {
|
|
152
2915
|
getConfig;
|
|
@@ -331,6 +3094,25 @@ var SkillUpdater = class {
|
|
|
331
3094
|
}
|
|
332
3095
|
return void 0;
|
|
333
3096
|
}
|
|
3097
|
+
/** 在解压目录里定位专家根目录;专家包根必须同时包含 AGENTS.md 和 SOUL.md。 */
|
|
3098
|
+
async locateExpertRoot(dir, depth) {
|
|
3099
|
+
if (depth > 2) return void 0;
|
|
3100
|
+
let entries;
|
|
3101
|
+
try {
|
|
3102
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
3103
|
+
} catch {
|
|
3104
|
+
return void 0;
|
|
3105
|
+
}
|
|
3106
|
+
const files = new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name));
|
|
3107
|
+
if (files.has("AGENTS.md") && files.has("SOUL.md")) return dir;
|
|
3108
|
+
for (const entry of entries) {
|
|
3109
|
+
if (entry.isDirectory()) {
|
|
3110
|
+
const found = await this.locateExpertRoot(path3.join(dir, entry.name), depth + 1);
|
|
3111
|
+
if (found) return found;
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
return void 0;
|
|
3115
|
+
}
|
|
334
3116
|
/**
|
|
335
3117
|
* 直接覆盖、不备份,但保证「不丢数据」:
|
|
336
3118
|
* 先把新内容暂存到同级临时目录 → 旧目录改名挪开 → 新内容 rename 换入 → 删掉挪开的旧目录。
|
|
@@ -394,37 +3176,114 @@ var SkillUpdater = class {
|
|
|
394
3176
|
});
|
|
395
3177
|
}
|
|
396
3178
|
}
|
|
3179
|
+
async installExpertZipFromUrl(url, targetDir) {
|
|
3180
|
+
const work = path3.join(this.tmpDir, `slp-expert-${randomUUID()}`);
|
|
3181
|
+
await fs3.mkdir(work, { recursive: true });
|
|
3182
|
+
try {
|
|
3183
|
+
const zipPath = path3.join(work, "pkg.zip");
|
|
3184
|
+
const res = await this.fetchImpl(url);
|
|
3185
|
+
if (!res.ok) return { success: false, message: `\u4E0B\u8F7D\u5931\u8D25: HTTP ${res.status}` };
|
|
3186
|
+
await fs3.writeFile(zipPath, Buffer.from(await res.arrayBuffer()));
|
|
3187
|
+
const staging = path3.join(work, "staging");
|
|
3188
|
+
await this.unzip(zipPath, staging);
|
|
3189
|
+
const expertRoot = await this.locateExpertRoot(staging, 0);
|
|
3190
|
+
if (!expertRoot) {
|
|
3191
|
+
return { success: false, message: "\u4E0B\u8F7D\u5305\u5185\u672A\u627E\u5230\u540C\u65F6\u542B AGENTS.md \u548C SOUL.md \u7684\u4E13\u5BB6\u6839\u76EE\u5F55" };
|
|
3192
|
+
}
|
|
3193
|
+
await this.replaceDir(expertRoot, targetDir);
|
|
3194
|
+
return { success: true, message: "\u5B89\u88C5\u6210\u529F" };
|
|
3195
|
+
} catch (err) {
|
|
3196
|
+
return { success: false, message: `\u6267\u884C\u51FA\u9519: ${err.message}` };
|
|
3197
|
+
} finally {
|
|
3198
|
+
await fs3.rm(work, { recursive: true, force: true }).catch(() => {
|
|
3199
|
+
});
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
397
3202
|
async manualInstall(options) {
|
|
398
|
-
const { code, force, targetDir } = options;
|
|
3203
|
+
const { code, force, targetDir, additionalTargetDirs = [], trace } = options;
|
|
399
3204
|
let { url, version } = options;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
3205
|
+
const startedAt = Date.now();
|
|
3206
|
+
let currentStage = "install.start";
|
|
3207
|
+
let work;
|
|
3208
|
+
const emit = (stage, data) => {
|
|
3209
|
+
currentStage = stage;
|
|
3210
|
+
try {
|
|
3211
|
+
trace?.(stage, data);
|
|
3212
|
+
} catch {
|
|
404
3213
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
await fs3.mkdir(work, { recursive: true });
|
|
3214
|
+
};
|
|
3215
|
+
emit("install.start", {
|
|
3216
|
+
code,
|
|
3217
|
+
version: version || "latest",
|
|
3218
|
+
force,
|
|
3219
|
+
hasDirectUrl: Boolean(url),
|
|
3220
|
+
targetCount: 1 + additionalTargetDirs.length
|
|
3221
|
+
});
|
|
414
3222
|
try {
|
|
3223
|
+
if (!code || code === "." || code === ".." || code.includes("/") || code.includes("\\") || code.includes("\0") || path3.basename(code) !== code) {
|
|
3224
|
+
const message = `\u975E\u6CD5\u7684 Skill code: ${code}`;
|
|
3225
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
3226
|
+
return { success: false, message };
|
|
3227
|
+
}
|
|
3228
|
+
if (!url) {
|
|
3229
|
+
const lookupStartedAt = Date.now();
|
|
3230
|
+
emit("download_url.lookup.start", { code, version: version || "latest" });
|
|
3231
|
+
const dl = await this.fetchDownloadUrl(code, version || "latest");
|
|
3232
|
+
if (!dl?.url) {
|
|
3233
|
+
const message = `\u65E0\u6CD5\u83B7\u53D6\u6280\u80FD ${code} \u7684\u4E0B\u8F7D\u5730\u5740`;
|
|
3234
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
3235
|
+
return { success: false, message };
|
|
3236
|
+
}
|
|
3237
|
+
url = dl.url;
|
|
3238
|
+
version = dl.version || version;
|
|
3239
|
+
emit("download_url.lookup.completed", {
|
|
3240
|
+
version: version || "latest",
|
|
3241
|
+
url,
|
|
3242
|
+
elapsedMs: Date.now() - lookupStartedAt
|
|
3243
|
+
});
|
|
3244
|
+
}
|
|
3245
|
+
const targetSkillPath = path3.join(targetDir, code);
|
|
3246
|
+
if (!force && await this.exists(targetSkillPath)) {
|
|
3247
|
+
const message = `\u6280\u80FD ${code} \u5DF2\u5B58\u5728\u4E8E\u76EE\u6807\u76EE\u5F55`;
|
|
3248
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
3249
|
+
return { success: false, message };
|
|
3250
|
+
}
|
|
3251
|
+
work = path3.join(this.tmpDir, `slp-manual-${randomUUID()}`);
|
|
3252
|
+
await fs3.mkdir(work, { recursive: true });
|
|
415
3253
|
const zipPath = path3.join(work, "pkg.zip");
|
|
3254
|
+
const downloadStartedAt = Date.now();
|
|
3255
|
+
emit("download.request.start", { url });
|
|
416
3256
|
const res = await this.fetchImpl(url);
|
|
3257
|
+
emit("download.headers.received", {
|
|
3258
|
+
status: res.status,
|
|
3259
|
+
contentLength: res.headers?.get("content-length") || void 0,
|
|
3260
|
+
contentType: res.headers?.get("content-type") || void 0,
|
|
3261
|
+
elapsedMs: Date.now() - downloadStartedAt
|
|
3262
|
+
});
|
|
417
3263
|
if (!res.ok) {
|
|
418
|
-
|
|
3264
|
+
const message = `\u4E0B\u8F7D\u5931\u8D25: HTTP ${res.status}`;
|
|
3265
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
3266
|
+
return { success: false, message };
|
|
419
3267
|
}
|
|
420
3268
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
3269
|
+
emit("download.body.completed", {
|
|
3270
|
+
bytes: buf.byteLength,
|
|
3271
|
+
elapsedMs: Date.now() - downloadStartedAt
|
|
3272
|
+
});
|
|
421
3273
|
await fs3.writeFile(zipPath, buf);
|
|
3274
|
+
emit("download.file.written", { bytes: buf.byteLength });
|
|
422
3275
|
const staging = path3.join(work, "staging");
|
|
3276
|
+
const unzipStartedAt = Date.now();
|
|
3277
|
+
emit("unzip.start", { extractor: "adm-zip" });
|
|
423
3278
|
await this.unzip(zipPath, staging);
|
|
3279
|
+
emit("unzip.completed", { elapsedMs: Date.now() - unzipStartedAt });
|
|
424
3280
|
const srcRoot = await this.locateSkillRoot(staging, 0);
|
|
425
3281
|
if (!srcRoot) {
|
|
426
|
-
|
|
3282
|
+
const message = `\u4E0B\u8F7D\u5305\u5185\u672A\u627E\u5230 SKILL.md\uFF0C\u975E\u6CD5\u7684\u6280\u80FD\u5305\u7ED3\u6784`;
|
|
3283
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
3284
|
+
return { success: false, message };
|
|
427
3285
|
}
|
|
3286
|
+
emit("skill_root.located");
|
|
428
3287
|
const metaPath = path3.join(srcRoot, ".meta.json");
|
|
429
3288
|
if (!await this.exists(metaPath)) {
|
|
430
3289
|
let parsedVersion = version || "unknown";
|
|
@@ -442,13 +3301,37 @@ var SkillUpdater = class {
|
|
|
442
3301
|
publishedAt: Date.now()
|
|
443
3302
|
}, null, 2));
|
|
444
3303
|
}
|
|
445
|
-
|
|
3304
|
+
const targets = [targetDir, ...additionalTargetDirs];
|
|
3305
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
3306
|
+
const rootDir = targets[index];
|
|
3307
|
+
const targetPath = path3.join(rootDir, code);
|
|
3308
|
+
const replaceStartedAt = Date.now();
|
|
3309
|
+
emit("target.replace.start", { targetDir: rootDir, targetIndex: index, targetCount: targets.length });
|
|
3310
|
+
await this.replaceDir(srcRoot, targetPath);
|
|
3311
|
+
emit("target.replace.completed", {
|
|
3312
|
+
targetDir: rootDir,
|
|
3313
|
+
targetIndex: index,
|
|
3314
|
+
targetCount: targets.length,
|
|
3315
|
+
elapsedMs: Date.now() - replaceStartedAt
|
|
3316
|
+
});
|
|
3317
|
+
}
|
|
3318
|
+
emit("install.completed", { elapsedMs: Date.now() - startedAt, targetCount: targets.length });
|
|
446
3319
|
return { success: true, message: `\u6280\u80FD ${code} \u5B89\u88C5/\u66F4\u65B0\u6210\u529F` };
|
|
447
3320
|
} catch (err) {
|
|
3321
|
+
emit("install.failed", {
|
|
3322
|
+
stage: currentStage,
|
|
3323
|
+
errorName: err?.name,
|
|
3324
|
+
message: err?.message || String(err),
|
|
3325
|
+
stack: err?.stack,
|
|
3326
|
+
elapsedMs: Date.now() - startedAt
|
|
3327
|
+
});
|
|
448
3328
|
return { success: false, message: `\u6267\u884C\u51FA\u9519: ${err.message}` };
|
|
449
3329
|
} finally {
|
|
450
|
-
|
|
451
|
-
|
|
3330
|
+
if (work) {
|
|
3331
|
+
await fs3.rm(work, { recursive: true, force: true }).catch(() => {
|
|
3332
|
+
});
|
|
3333
|
+
emit("cleanup.completed", { elapsedMs: Date.now() - startedAt });
|
|
3334
|
+
}
|
|
452
3335
|
}
|
|
453
3336
|
}
|
|
454
3337
|
};
|
|
@@ -822,6 +3705,9 @@ function parseCore(v) {
|
|
|
822
3705
|
}
|
|
823
3706
|
return nums.length > 0 ? nums : null;
|
|
824
3707
|
}
|
|
3708
|
+
function isComparableVersion(v) {
|
|
3709
|
+
return parseCore(v) !== null;
|
|
3710
|
+
}
|
|
825
3711
|
function compareVersions(a, b) {
|
|
826
3712
|
const na = parseCore(a);
|
|
827
3713
|
const nb = parseCore(b);
|
|
@@ -1275,18 +4161,18 @@ var ConfigSync = class {
|
|
|
1275
4161
|
};
|
|
1276
4162
|
|
|
1277
4163
|
// src/reporter.ts
|
|
1278
|
-
import
|
|
1279
|
-
import
|
|
4164
|
+
import fs6 from "node:fs/promises";
|
|
4165
|
+
import path7 from "node:path";
|
|
1280
4166
|
|
|
1281
4167
|
// src/identity.ts
|
|
1282
4168
|
import os3 from "node:os";
|
|
1283
|
-
import
|
|
1284
|
-
import
|
|
1285
|
-
var execFileAsync2 = promisify2(execFile2);
|
|
4169
|
+
import fs5 from "node:fs/promises";
|
|
4170
|
+
import path6 from "node:path";
|
|
1286
4171
|
async function getGitConfigValue(key) {
|
|
1287
4172
|
try {
|
|
1288
|
-
const
|
|
1289
|
-
|
|
4173
|
+
const gitConfigPath = path6.join(os3.homedir(), ".gitconfig");
|
|
4174
|
+
const content = await fs5.readFile(gitConfigPath, "utf-8");
|
|
4175
|
+
return parseGitConfigValue(content, key);
|
|
1290
4176
|
} catch {
|
|
1291
4177
|
console.warn(
|
|
1292
4178
|
`[skill-logger-plugin] git config --global ${key} \u672A\u8BBE\u7F6E\u3002\u53EF\u6267\u884C\uFF1Agit config --global ${key} '<value>'`
|
|
@@ -1294,6 +4180,26 @@ async function getGitConfigValue(key) {
|
|
|
1294
4180
|
return "";
|
|
1295
4181
|
}
|
|
1296
4182
|
}
|
|
4183
|
+
function parseGitConfigValue(content, key) {
|
|
4184
|
+
const [section, name] = key.split(".");
|
|
4185
|
+
if (!section || !name) return "";
|
|
4186
|
+
let inTargetSection = false;
|
|
4187
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
4188
|
+
const line = rawLine.trim();
|
|
4189
|
+
if (!line || line.startsWith("#") || line.startsWith(";")) continue;
|
|
4190
|
+
const sectionMatch = /^\[([^\]]+)\]$/.exec(line);
|
|
4191
|
+
if (sectionMatch) {
|
|
4192
|
+
inTargetSection = sectionMatch[1].trim() === section;
|
|
4193
|
+
continue;
|
|
4194
|
+
}
|
|
4195
|
+
if (!inTargetSection) continue;
|
|
4196
|
+
const kv = /^([A-Za-z0-9_.-]+)\s*=\s*(.*)$/.exec(line);
|
|
4197
|
+
if (kv?.[1] === name) {
|
|
4198
|
+
return kv[2].trim().replace(/^"|"$/g, "");
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
return "";
|
|
4202
|
+
}
|
|
1297
4203
|
var GitIdentityProvider = class {
|
|
1298
4204
|
cached;
|
|
1299
4205
|
async getIdentity() {
|
|
@@ -1345,9 +4251,9 @@ var Reporter = class {
|
|
|
1345
4251
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
1346
4252
|
const logLine = `[${ts}] [${level}] [skill-logger-plugin] ${msg}
|
|
1347
4253
|
`;
|
|
1348
|
-
const logDir =
|
|
1349
|
-
await
|
|
1350
|
-
await
|
|
4254
|
+
const logDir = path7.dirname(this.paths.eventsLogPath);
|
|
4255
|
+
await fs6.mkdir(logDir, { recursive: true });
|
|
4256
|
+
await fs6.appendFile(path7.join(logDir, "skill-logger.err.log"), logLine);
|
|
1351
4257
|
if (level === "INFO" && this.isDebug) {
|
|
1352
4258
|
console.log("[skill-logger-plugin/reporter]", ...args);
|
|
1353
4259
|
} else if (level === "WARN" || level === "ERROR") {
|
|
@@ -1380,8 +4286,8 @@ var Reporter = class {
|
|
|
1380
4286
|
} catch {
|
|
1381
4287
|
return;
|
|
1382
4288
|
}
|
|
1383
|
-
await
|
|
1384
|
-
await
|
|
4289
|
+
await fs6.mkdir(path7.dirname(this.paths.eventsLogPath), { recursive: true });
|
|
4290
|
+
await fs6.appendFile(this.paths.eventsLogPath, line + "\n");
|
|
1385
4291
|
} catch (err) {
|
|
1386
4292
|
void this.writeFallbackLog("ERROR", "\u5199\u4E8B\u4EF6\u65E5\u5FD7\u5931\u8D25", this.paths.eventsLogPath, err);
|
|
1387
4293
|
}
|
|
@@ -1451,19 +4357,19 @@ var Reporter = class {
|
|
|
1451
4357
|
void this.writeFallbackLog("WARN", "flush skipped: reportBaseUrl \u6CA1\u6709\u914D\u7F6E\uFF01\u8BF7\u68C0\u67E5 openclaw.json \u63D2\u4EF6\u914D\u7F6E\u662F\u5426\u6B63\u786E\u52A0\u8F7D\u3002");
|
|
1452
4358
|
return;
|
|
1453
4359
|
}
|
|
1454
|
-
const logDir =
|
|
4360
|
+
const logDir = path7.dirname(this.paths.eventsLogPath);
|
|
1455
4361
|
try {
|
|
1456
|
-
await
|
|
4362
|
+
await fs6.access(this.paths.eventsLogPath);
|
|
1457
4363
|
const timestamp = Date.now();
|
|
1458
|
-
const rotatedPath =
|
|
1459
|
-
await
|
|
1460
|
-
this.debug(`Rotated active log to ${
|
|
4364
|
+
const rotatedPath = path7.join(logDir, `events.${timestamp}.jsonl`);
|
|
4365
|
+
await fs6.rename(this.paths.eventsLogPath, rotatedPath);
|
|
4366
|
+
this.debug(`Rotated active log to ${path7.basename(rotatedPath)}`);
|
|
1461
4367
|
} catch {
|
|
1462
4368
|
}
|
|
1463
4369
|
let files = [];
|
|
1464
4370
|
try {
|
|
1465
|
-
const dirEntries = await
|
|
1466
|
-
files = dirEntries.filter((f) => f.startsWith("events.") && f.endsWith(".jsonl") && f !== "events.jsonl").map((f) =>
|
|
4371
|
+
const dirEntries = await fs6.readdir(logDir);
|
|
4372
|
+
files = dirEntries.filter((f) => f.startsWith("events.") && f.endsWith(".jsonl") && f !== "events.jsonl").map((f) => path7.join(logDir, f));
|
|
1467
4373
|
} catch {
|
|
1468
4374
|
return;
|
|
1469
4375
|
}
|
|
@@ -1476,10 +4382,10 @@ var Reporter = class {
|
|
|
1476
4382
|
const url = config.reportBaseUrl.replace(/\/$/, "") + "/skill_report/batch";
|
|
1477
4383
|
for (const filePath of files) {
|
|
1478
4384
|
try {
|
|
1479
|
-
const content = await
|
|
4385
|
+
const content = await fs6.readFile(filePath, "utf-8");
|
|
1480
4386
|
const lines = this.linesOf(content);
|
|
1481
4387
|
if (lines.length === 0) {
|
|
1482
|
-
await
|
|
4388
|
+
await fs6.unlink(filePath);
|
|
1483
4389
|
continue;
|
|
1484
4390
|
}
|
|
1485
4391
|
let cursor = 0;
|
|
@@ -1508,8 +4414,8 @@ var Reporter = class {
|
|
|
1508
4414
|
if (config.authToken) headers.Authorization = config.authToken;
|
|
1509
4415
|
const res = await this.fetchImpl(url, { method: "POST", headers, body });
|
|
1510
4416
|
if (!res.ok) {
|
|
1511
|
-
const errBody = await res.text().catch(() => "\u65E0\u6CD5\u8BFB\u53D6\u54CD\u5E94\u4F53");
|
|
1512
|
-
await this.writeFallbackLog("ERROR", `\u6279\u91CF\u4E0A\u62A5\u5931\u8D25 (\u6587\u4EF6 ${
|
|
4417
|
+
const errBody = await res.text?.().catch(() => "\u65E0\u6CD5\u8BFB\u53D6\u54CD\u5E94\u4F53") ?? "\u65E0\u6CD5\u8BFB\u53D6\u54CD\u5E94\u4F53";
|
|
4418
|
+
await this.writeFallbackLog("ERROR", `\u6279\u91CF\u4E0A\u62A5\u5931\u8D25 (\u6587\u4EF6 ${path7.basename(filePath)}), HTTP`, res.status, "\u670D\u52A1\u7AEF\u8FD4\u56DE\u4FE1\u606F:", errBody);
|
|
1513
4419
|
if (res.status === 400 || res.status === 413 || res.status === 422) {
|
|
1514
4420
|
await this.writeFallbackLog("WARN", `\u62A5\u6587\u88AB\u670D\u52A1\u5668\u6C38\u4E45\u62D2\u7EDD\uFF0C\u4E22\u5F03\u8BE5\u6279\u6B21\u4EE5\u91CA\u653E\u961F\u5217`);
|
|
1515
4421
|
cursor += slice.length;
|
|
@@ -1518,17 +4424,17 @@ var Reporter = class {
|
|
|
1518
4424
|
allSuccess = false;
|
|
1519
4425
|
break;
|
|
1520
4426
|
}
|
|
1521
|
-
this.debug(`Successfully reported batch of ${events.length} events from ${
|
|
4427
|
+
this.debug(`Successfully reported batch of ${events.length} events from ${path7.basename(filePath)}`);
|
|
1522
4428
|
cursor += slice.length;
|
|
1523
4429
|
}
|
|
1524
4430
|
if (allSuccess) {
|
|
1525
|
-
await
|
|
1526
|
-
this.debug(`Deleted fully processed file: ${
|
|
4431
|
+
await fs6.unlink(filePath);
|
|
4432
|
+
this.debug(`Deleted fully processed file: ${path7.basename(filePath)}`);
|
|
1527
4433
|
} else {
|
|
1528
|
-
this.debug(`File ${
|
|
4434
|
+
this.debug(`File ${path7.basename(filePath)} partially failed. Keeping it for next flush.`);
|
|
1529
4435
|
}
|
|
1530
4436
|
} catch (err) {
|
|
1531
|
-
await this.writeFallbackLog("ERROR", `\u5904\u7406\u6587\u4EF6 ${
|
|
4437
|
+
await this.writeFallbackLog("ERROR", `\u5904\u7406\u6587\u4EF6 ${path7.basename(filePath)} \u5F02\u5E38:`, err);
|
|
1532
4438
|
}
|
|
1533
4439
|
}
|
|
1534
4440
|
} catch (err) {
|
|
@@ -1539,29 +4445,297 @@ var Reporter = class {
|
|
|
1539
4445
|
}
|
|
1540
4446
|
};
|
|
1541
4447
|
|
|
4448
|
+
// src/expert-skill-layout.ts
|
|
4449
|
+
import fs7 from "node:fs/promises";
|
|
4450
|
+
import path8 from "node:path";
|
|
4451
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4452
|
+
var ASSISTANT_WORKSPACE_RE = /^workspace-assistant-\d{5,}$/;
|
|
4453
|
+
var REPAIR_RESIDUE_RE = /^\.(.+)\.repair-(old|new)-(.+)$/;
|
|
4454
|
+
async function lstatOrUndefined(filePath) {
|
|
4455
|
+
try {
|
|
4456
|
+
return await fs7.lstat(filePath);
|
|
4457
|
+
} catch (error) {
|
|
4458
|
+
if (error?.code === "ENOENT") return void 0;
|
|
4459
|
+
throw error;
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
async function isRegularFile(filePath) {
|
|
4463
|
+
const stat = await lstatOrUndefined(filePath);
|
|
4464
|
+
return Boolean(stat?.isFile() && !stat.isSymbolicLink());
|
|
4465
|
+
}
|
|
4466
|
+
async function removeRealDirectory(dirPath) {
|
|
4467
|
+
const stat = await lstatOrUndefined(dirPath);
|
|
4468
|
+
if (!stat) return;
|
|
4469
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
4470
|
+
throw new Error(`\u62D2\u7EDD\u6E05\u7406\u975E\u771F\u5B9E\u76EE\u5F55: ${dirPath}`);
|
|
4471
|
+
}
|
|
4472
|
+
await fs7.rm(dirPath, { recursive: true });
|
|
4473
|
+
}
|
|
4474
|
+
async function removeNestedDirectoryIfPresent(dirPath) {
|
|
4475
|
+
const stat = await lstatOrUndefined(dirPath);
|
|
4476
|
+
if (!stat) return;
|
|
4477
|
+
if (stat.isSymbolicLink()) throw new Error(`\u62D2\u7EDD\u6E05\u7406\u7B26\u53F7\u94FE\u63A5: ${dirPath}`);
|
|
4478
|
+
if (stat.isDirectory()) await fs7.rm(dirPath, { recursive: true });
|
|
4479
|
+
}
|
|
4480
|
+
async function recoverRepairResidues(skillsRoot, entries, result) {
|
|
4481
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4482
|
+
for (const entry of entries) {
|
|
4483
|
+
const match2 = REPAIR_RESIDUE_RE.exec(entry.name);
|
|
4484
|
+
if (!match2) continue;
|
|
4485
|
+
const group = groups.get(match2[1]) ?? { old: [], stage: [] };
|
|
4486
|
+
group[match2[2] === "old" ? "old" : "stage"].push(path8.join(skillsRoot, entry.name));
|
|
4487
|
+
groups.set(match2[1], group);
|
|
4488
|
+
}
|
|
4489
|
+
for (const [code, group] of groups) {
|
|
4490
|
+
const targetDir = path8.join(skillsRoot, code);
|
|
4491
|
+
try {
|
|
4492
|
+
const targetStat = await lstatOrUndefined(targetDir);
|
|
4493
|
+
if (targetStat?.isSymbolicLink() || targetStat && !targetStat.isDirectory()) {
|
|
4494
|
+
throw new Error(`\u89C4\u8303\u8DEF\u5F84\u4E0D\u662F\u53EF\u5B89\u5168\u64CD\u4F5C\u7684\u771F\u5B9E\u76EE\u5F55: ${targetDir}`);
|
|
4495
|
+
}
|
|
4496
|
+
group.old.sort().reverse();
|
|
4497
|
+
if (!targetStat && group.old.length > 0) {
|
|
4498
|
+
const restore = group.old.shift();
|
|
4499
|
+
const restoreStat = await lstatOrUndefined(restore);
|
|
4500
|
+
if (!restoreStat?.isDirectory() || restoreStat.isSymbolicLink()) {
|
|
4501
|
+
throw new Error(`\u62D2\u7EDD\u4ECE\u975E\u771F\u5B9E\u76EE\u5F55\u6062\u590D: ${restore}`);
|
|
4502
|
+
}
|
|
4503
|
+
await fs7.rename(restore, targetDir);
|
|
4504
|
+
}
|
|
4505
|
+
if (await lstatOrUndefined(targetDir)) {
|
|
4506
|
+
for (const residue of [...group.old, ...group.stage]) {
|
|
4507
|
+
await removeRealDirectory(residue);
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
} catch (error) {
|
|
4511
|
+
result.errors.push({ path: targetDir, message: error?.message || String(error) });
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
async function promoteNestedSkill(sourceDir, targetDir) {
|
|
4516
|
+
const parent = path8.dirname(targetDir);
|
|
4517
|
+
const tag = `${Date.now()}-${randomUUID2().slice(0, 8)}`;
|
|
4518
|
+
const stage = path8.join(parent, `.${path8.basename(targetDir)}.repair-new-${tag}`);
|
|
4519
|
+
const old = path8.join(parent, `.${path8.basename(targetDir)}.repair-old-${tag}`);
|
|
4520
|
+
let movedOld = false;
|
|
4521
|
+
try {
|
|
4522
|
+
await fs7.cp(sourceDir, stage, { recursive: true });
|
|
4523
|
+
await removeNestedDirectoryIfPresent(path8.join(stage, path8.basename(targetDir)));
|
|
4524
|
+
await fs7.rename(targetDir, old);
|
|
4525
|
+
movedOld = true;
|
|
4526
|
+
await fs7.rename(stage, targetDir);
|
|
4527
|
+
} catch (error) {
|
|
4528
|
+
const rollbackErrors = [];
|
|
4529
|
+
try {
|
|
4530
|
+
await removeRealDirectory(stage);
|
|
4531
|
+
} catch (cleanupError) {
|
|
4532
|
+
rollbackErrors.push(`\u6E05\u7406\u6682\u5B58\u76EE\u5F55\u5931\u8D25: ${cleanupError?.message || String(cleanupError)}`);
|
|
4533
|
+
}
|
|
4534
|
+
if (movedOld) {
|
|
4535
|
+
try {
|
|
4536
|
+
await fs7.rename(old, targetDir);
|
|
4537
|
+
} catch (restoreError) {
|
|
4538
|
+
rollbackErrors.push(`\u6062\u590D\u65E7\u76EE\u5F55\u5931\u8D25: ${restoreError?.message || String(restoreError)}`);
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
if (rollbackErrors.length > 0) {
|
|
4542
|
+
throw new Error(`${error?.message || String(error)}; ${rollbackErrors.join("; ")}`);
|
|
4543
|
+
}
|
|
4544
|
+
throw error;
|
|
4545
|
+
}
|
|
4546
|
+
await removeRealDirectory(old);
|
|
4547
|
+
}
|
|
4548
|
+
async function repairNestedExpertSkillLayouts(openclawRoot) {
|
|
4549
|
+
const result = {
|
|
4550
|
+
scannedWorkspaces: 0,
|
|
4551
|
+
repaired: [],
|
|
4552
|
+
skipped: [],
|
|
4553
|
+
errors: []
|
|
4554
|
+
};
|
|
4555
|
+
let workspaceEntries;
|
|
4556
|
+
try {
|
|
4557
|
+
workspaceEntries = await fs7.readdir(openclawRoot, { withFileTypes: true });
|
|
4558
|
+
} catch (error) {
|
|
4559
|
+
result.errors.push({ path: openclawRoot, message: error?.message || String(error) });
|
|
4560
|
+
return result;
|
|
4561
|
+
}
|
|
4562
|
+
for (const workspaceEntry of workspaceEntries) {
|
|
4563
|
+
if (!workspaceEntry.isDirectory() || !ASSISTANT_WORKSPACE_RE.test(workspaceEntry.name)) continue;
|
|
4564
|
+
result.scannedWorkspaces += 1;
|
|
4565
|
+
const skillsRoot = path8.join(openclawRoot, workspaceEntry.name, ".user", "skills");
|
|
4566
|
+
let skillEntries;
|
|
4567
|
+
try {
|
|
4568
|
+
skillEntries = await fs7.readdir(skillsRoot, { withFileTypes: true });
|
|
4569
|
+
await recoverRepairResidues(skillsRoot, skillEntries, result);
|
|
4570
|
+
skillEntries = await fs7.readdir(skillsRoot, { withFileTypes: true });
|
|
4571
|
+
} catch (error) {
|
|
4572
|
+
if (error?.code !== "ENOENT") {
|
|
4573
|
+
result.errors.push({ path: skillsRoot, message: error?.message || String(error) });
|
|
4574
|
+
}
|
|
4575
|
+
continue;
|
|
4576
|
+
}
|
|
4577
|
+
for (const skillEntry of skillEntries) {
|
|
4578
|
+
if (!skillEntry.isDirectory() || skillEntry.name.startsWith(".")) continue;
|
|
4579
|
+
const outerDir = path8.join(skillsRoot, skillEntry.name);
|
|
4580
|
+
try {
|
|
4581
|
+
const candidates = [];
|
|
4582
|
+
const outerHasSkill = await isRegularFile(path8.join(outerDir, "SKILL.md"));
|
|
4583
|
+
if (outerHasSkill) {
|
|
4584
|
+
const version = await readSkillVersion(outerDir);
|
|
4585
|
+
if (!version) {
|
|
4586
|
+
result.skipped.push(outerDir);
|
|
4587
|
+
continue;
|
|
4588
|
+
}
|
|
4589
|
+
candidates.push({ dir: outerDir, version });
|
|
4590
|
+
}
|
|
4591
|
+
let cursor = outerDir;
|
|
4592
|
+
let nestedCount = 0;
|
|
4593
|
+
while (true) {
|
|
4594
|
+
const nestedDir = path8.join(cursor, skillEntry.name);
|
|
4595
|
+
const nestedStat = await lstatOrUndefined(nestedDir);
|
|
4596
|
+
if (!nestedStat) break;
|
|
4597
|
+
if (nestedStat.isSymbolicLink()) {
|
|
4598
|
+
throw new Error(`\u62D2\u7EDD\u8DDF\u968F\u540C\u540D\u7B26\u53F7\u94FE\u63A5: ${nestedDir}`);
|
|
4599
|
+
}
|
|
4600
|
+
if (!nestedStat.isDirectory()) break;
|
|
4601
|
+
cursor = nestedDir;
|
|
4602
|
+
const skillMd = path8.join(nestedDir, "SKILL.md");
|
|
4603
|
+
const skillStat = await lstatOrUndefined(skillMd);
|
|
4604
|
+
if (skillStat?.isSymbolicLink()) {
|
|
4605
|
+
throw new Error(`\u62D2\u7EDD\u8BFB\u53D6\u7B26\u53F7\u94FE\u63A5 SKILL.md: ${skillMd}`);
|
|
4606
|
+
}
|
|
4607
|
+
if (!skillStat?.isFile()) continue;
|
|
4608
|
+
nestedCount += 1;
|
|
4609
|
+
const version = await readSkillVersion(nestedDir);
|
|
4610
|
+
if (!version) {
|
|
4611
|
+
result.skipped.push(outerDir);
|
|
4612
|
+
candidates.length = 0;
|
|
4613
|
+
break;
|
|
4614
|
+
}
|
|
4615
|
+
candidates.push({ dir: nestedDir, version });
|
|
4616
|
+
}
|
|
4617
|
+
if (nestedCount === 0 || candidates.length === 0) continue;
|
|
4618
|
+
if (candidates.some((candidate) => !isComparableVersion(candidate.version))) {
|
|
4619
|
+
result.skipped.push(outerDir);
|
|
4620
|
+
continue;
|
|
4621
|
+
}
|
|
4622
|
+
let source = candidates[0];
|
|
4623
|
+
for (const candidate of candidates.slice(1)) {
|
|
4624
|
+
if (compareVersions(candidate.version, source.version) >= 0) source = candidate;
|
|
4625
|
+
}
|
|
4626
|
+
if (source.dir === outerDir) {
|
|
4627
|
+
result.skipped.push(outerDir);
|
|
4628
|
+
continue;
|
|
4629
|
+
}
|
|
4630
|
+
await promoteNestedSkill(source.dir, outerDir);
|
|
4631
|
+
result.repaired.push(outerDir);
|
|
4632
|
+
} catch (error) {
|
|
4633
|
+
result.errors.push({ path: outerDir, message: error?.message || String(error) });
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
return result;
|
|
4638
|
+
}
|
|
4639
|
+
|
|
1542
4640
|
// src/ws-client.ts
|
|
1543
4641
|
import WebSocket from "ws";
|
|
1544
|
-
import
|
|
1545
|
-
import
|
|
4642
|
+
import path9 from "path";
|
|
4643
|
+
import fs8 from "fs/promises";
|
|
4644
|
+
import { DatabaseSync } from "node:sqlite";
|
|
1546
4645
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
1547
4646
|
var HEARTBEAT_ACK_TIMEOUT_MS = 75e3;
|
|
1548
4647
|
var AGENT_SCAN_INTERVAL_MS = 3 * 60 * 1e3;
|
|
1549
|
-
var ASSISTANT_WORKSPACE_PREFIX = "workspace-assistant-";
|
|
1550
4648
|
var ASSISTANT_AGENT_PREFIX = "assistant-";
|
|
1551
4649
|
var ASSISTANT_WORKSPACE_ID_RE = /^\d{5,}$/;
|
|
1552
|
-
function
|
|
1553
|
-
if (!
|
|
1554
|
-
const
|
|
1555
|
-
if (!
|
|
1556
|
-
|
|
4650
|
+
function enabledAgentIdsFromAccounts(config) {
|
|
4651
|
+
if (!config || typeof config !== "object") return [];
|
|
4652
|
+
const channels = config.channels;
|
|
4653
|
+
if (!channels || typeof channels !== "object") return [];
|
|
4654
|
+
const cworkConfig = channels.xg_cwork_im;
|
|
4655
|
+
if (!cworkConfig || typeof cworkConfig !== "object") return [];
|
|
4656
|
+
const accounts = cworkConfig.accounts;
|
|
4657
|
+
if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) return [];
|
|
4658
|
+
const agentIds = /* @__PURE__ */ new Set();
|
|
4659
|
+
for (const account of Object.values(accounts)) {
|
|
4660
|
+
if (!account || typeof account !== "object" || account.enabled === false) continue;
|
|
4661
|
+
if (typeof account.agentId !== "string") continue;
|
|
4662
|
+
const agentId = account.agentId.trim();
|
|
4663
|
+
if (agentId) agentIds.add(agentId);
|
|
4664
|
+
}
|
|
4665
|
+
return [...agentIds];
|
|
4666
|
+
}
|
|
4667
|
+
function resolveSkillInstallTarget(config, userId) {
|
|
4668
|
+
if (!config || typeof config !== "object") throw new Error("openclaw.json \u914D\u7F6E\u65E0\u6548");
|
|
4669
|
+
const root = config;
|
|
4670
|
+
const accounts = root.channels?.xg_cwork_im?.accounts;
|
|
4671
|
+
if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) {
|
|
4672
|
+
throw new Error(`\u672A\u627E\u5230 userId=${userId} \u7684 xg_cwork_im account`);
|
|
4673
|
+
}
|
|
4674
|
+
const matched = Object.entries(accounts).filter(([, account2]) => account2 && typeof account2 === "object" && account2.agentId === userId);
|
|
4675
|
+
if (matched.length !== 1) {
|
|
4676
|
+
throw new Error(matched.length > 1 ? `userId=${userId} \u5B58\u5728\u591A\u4E2A xg_cwork_im account\uFF0C\u65E0\u6CD5\u786E\u5B9A\u5B89\u88C5\u76EE\u5F55` : `\u672A\u627E\u5230 userId=${userId} \u7684 xg_cwork_im account`);
|
|
4677
|
+
}
|
|
4678
|
+
const [accountId, account] = matched[0];
|
|
4679
|
+
if (account.enabled === false) throw new Error(`userId=${userId} \u5BF9\u5E94 Agent \u5DF2\u7981\u7528`);
|
|
4680
|
+
const bindingAccountIds = /* @__PURE__ */ new Set([accountId, userId]);
|
|
4681
|
+
const bindings = Array.isArray(root.bindings) ? root.bindings : [];
|
|
4682
|
+
const binding = bindings.find((item) => {
|
|
4683
|
+
if (!item || typeof item !== "object") return false;
|
|
4684
|
+
const candidate = item;
|
|
4685
|
+
return candidate.match?.channel === "xg_cwork_im" && typeof candidate.match.accountId === "string" && bindingAccountIds.has(candidate.match.accountId) && typeof candidate.agentId === "string" && candidate.agentId.length > 0;
|
|
4686
|
+
});
|
|
4687
|
+
const localAgentId = typeof binding?.agentId === "string" ? binding.agentId : userId;
|
|
4688
|
+
const list = Array.isArray(root.agents?.list) ? root.agents.list : [];
|
|
4689
|
+
const agent = list.find(
|
|
4690
|
+
(item) => Boolean(item) && typeof item === "object" && item.id === localAgentId
|
|
4691
|
+
);
|
|
4692
|
+
if (!agent) throw new Error(`\u672A\u627E\u5230\u672C\u5730 Agent \u914D\u7F6E: ${localAgentId}`);
|
|
4693
|
+
const workspace = typeof agent.workspace === "string" ? agent.workspace : root.agents?.defaults?.workspace;
|
|
4694
|
+
if (typeof workspace !== "string" || !workspace.trim()) {
|
|
4695
|
+
throw new Error(`\u672C\u5730 Agent ${localAgentId} \u672A\u914D\u7F6E workspace`);
|
|
4696
|
+
}
|
|
4697
|
+
return { skillsDir: path9.join(workspace, "skills"), localAgentId };
|
|
1557
4698
|
}
|
|
1558
4699
|
function normalizeAssistantUserId(userId) {
|
|
1559
|
-
const safeUserId =
|
|
4700
|
+
const safeUserId = path9.basename(userId);
|
|
1560
4701
|
if (safeUserId !== userId) return void 0;
|
|
1561
4702
|
const pureId = safeUserId.startsWith(ASSISTANT_AGENT_PREFIX) ? safeUserId.slice(ASSISTANT_AGENT_PREFIX.length) : safeUserId;
|
|
1562
4703
|
if (!ASSISTANT_WORKSPACE_ID_RE.test(pureId)) return void 0;
|
|
1563
4704
|
return pureId;
|
|
1564
4705
|
}
|
|
4706
|
+
function normalizeCommandCode(code) {
|
|
4707
|
+
if (typeof code !== "string" || code.length === 0 || code === "." || code === "..") return void 0;
|
|
4708
|
+
if (code.includes("/") || code.includes("\\") || code.includes("\0")) return void 0;
|
|
4709
|
+
if (path9.basename(code) !== code) return void 0;
|
|
4710
|
+
return code;
|
|
4711
|
+
}
|
|
4712
|
+
function shouldSyncBuiltInTemplate(action, isBuiltIn) {
|
|
4713
|
+
return action === "UPDATE_SKILL" && isBuiltIn === true;
|
|
4714
|
+
}
|
|
4715
|
+
async function findInstalledExpertSkillsRoot(rootPath, pureId, code) {
|
|
4716
|
+
const skillsRoot = path9.join(rootPath, `workspace-assistant-${pureId}`, ".user", "skills");
|
|
4717
|
+
try {
|
|
4718
|
+
const stat = await fs8.stat(path9.join(skillsRoot, code));
|
|
4719
|
+
return stat.isDirectory() ? skillsRoot : void 0;
|
|
4720
|
+
} catch {
|
|
4721
|
+
return void 0;
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
function defaultOpenclawSqlitePath() {
|
|
4725
|
+
return path9.join(openclawHome(), "state", "openclaw.sqlite");
|
|
4726
|
+
}
|
|
4727
|
+
function readCronJobsByAgentId(agentId, sqlitePath = defaultOpenclawSqlitePath(), onError) {
|
|
4728
|
+
let db;
|
|
4729
|
+
try {
|
|
4730
|
+
db = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
4731
|
+
return db.prepare("SELECT * FROM cron_jobs WHERE agent_id = ?").all(agentId);
|
|
4732
|
+
} catch (err) {
|
|
4733
|
+
onError?.(err);
|
|
4734
|
+
return [];
|
|
4735
|
+
} finally {
|
|
4736
|
+
db?.close();
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
1565
4739
|
var GatewayWsClient = class {
|
|
1566
4740
|
ws = null;
|
|
1567
4741
|
options;
|
|
@@ -1588,16 +4762,35 @@ var GatewayWsClient = class {
|
|
|
1588
4762
|
}
|
|
1589
4763
|
}
|
|
1590
4764
|
logLine += "\n";
|
|
1591
|
-
const logsDir =
|
|
1592
|
-
|
|
1593
|
-
const logPath =
|
|
1594
|
-
|
|
4765
|
+
const logsDir = path9.join(openclawHome(), "logs");
|
|
4766
|
+
fs8.mkdir(logsDir, { recursive: true }).then(() => {
|
|
4767
|
+
const logPath = path9.join(logsDir, "skill-logger.err");
|
|
4768
|
+
fs8.appendFile(logPath, logLine).catch(() => {
|
|
1595
4769
|
});
|
|
1596
4770
|
}).catch(() => {
|
|
1597
4771
|
});
|
|
1598
4772
|
} catch (e) {
|
|
1599
4773
|
}
|
|
1600
4774
|
}
|
|
4775
|
+
createInstallTrace(context) {
|
|
4776
|
+
return (stage, data) => {
|
|
4777
|
+
this.appendLogToFile(stage === "install.failed" ? "ERROR" : "INFO", "Install", stage, {
|
|
4778
|
+
...context,
|
|
4779
|
+
...data
|
|
4780
|
+
});
|
|
4781
|
+
};
|
|
4782
|
+
}
|
|
4783
|
+
/** 普通 Skill 的所有读写操作共用这一个配置驱动的寻址入口。 */
|
|
4784
|
+
async resolveRegularSkillTarget(userId) {
|
|
4785
|
+
const configPath = path9.join(openclawHome(), "openclaw.json");
|
|
4786
|
+
let config;
|
|
4787
|
+
try {
|
|
4788
|
+
config = JSON.parse(await fs8.readFile(configPath, "utf-8"));
|
|
4789
|
+
} catch (err) {
|
|
4790
|
+
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6 openclaw.json: ${err?.message || String(err)}`);
|
|
4791
|
+
}
|
|
4792
|
+
return resolveSkillInstallTarget(config, userId).skillsDir;
|
|
4793
|
+
}
|
|
1601
4794
|
constructor(options) {
|
|
1602
4795
|
this.options = options;
|
|
1603
4796
|
}
|
|
@@ -1693,26 +4886,26 @@ var GatewayWsClient = class {
|
|
|
1693
4886
|
}
|
|
1694
4887
|
});
|
|
1695
4888
|
}
|
|
1696
|
-
/**
|
|
1697
|
-
* 扫描 OpenClaw 根目录下的 workspace-assistant-{userId} 目录。
|
|
1698
|
-
* userId 必须是至少 5 位数字。
|
|
1699
|
-
*/
|
|
4889
|
+
/** 从 openclaw.json 的 xg_cwork_im accounts 读取当前启用的 agent。 */
|
|
1700
4890
|
async scanAndReportAgents(isInitialReport) {
|
|
1701
4891
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
|
1702
4892
|
try {
|
|
1703
|
-
const
|
|
1704
|
-
let
|
|
4893
|
+
const configPath = path9.join(openclawHome(), "openclaw.json");
|
|
4894
|
+
let rawConfig;
|
|
1705
4895
|
try {
|
|
1706
|
-
|
|
4896
|
+
rawConfig = await fs8.readFile(configPath, "utf-8");
|
|
1707
4897
|
} catch (e) {
|
|
1708
|
-
this.appendLogToFile("WARN", "AgentScan", "OpenClaw
|
|
4898
|
+
this.appendLogToFile("WARN", "AgentScan", "OpenClaw config is not readable; skipping this scan cycle", e);
|
|
1709
4899
|
return;
|
|
1710
4900
|
}
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
4901
|
+
let config;
|
|
4902
|
+
try {
|
|
4903
|
+
config = JSON.parse(rawConfig);
|
|
4904
|
+
} catch (e) {
|
|
4905
|
+
this.appendLogToFile("WARN", "AgentScan", "OpenClaw config is invalid JSON; skipping this scan cycle", e);
|
|
4906
|
+
return;
|
|
1715
4907
|
}
|
|
4908
|
+
const newAgentIds = new Set(enabledAgentIdsFromAccounts(config));
|
|
1716
4909
|
let changed = false;
|
|
1717
4910
|
if (newAgentIds.size !== this.currentAgentIds.size) {
|
|
1718
4911
|
changed = true;
|
|
@@ -1849,22 +5042,55 @@ var GatewayWsClient = class {
|
|
|
1849
5042
|
* 核心指令分发中心:完全跳过沙盒,基于 userId 直接进行底层物理文件操作
|
|
1850
5043
|
*/
|
|
1851
5044
|
async handleMessage(msg) {
|
|
1852
|
-
const { action, userId, code, url, force, version, replyId } = msg;
|
|
1853
|
-
this.appendLogToFile("INFO", "Command", `Received WS message`, {
|
|
1854
|
-
|
|
1855
|
-
|
|
5045
|
+
const { action, userId, code, url, force, version, replyId, isBuiltIn } = msg;
|
|
5046
|
+
this.appendLogToFile("INFO", "Command", `Received WS message`, {
|
|
5047
|
+
action,
|
|
5048
|
+
userId,
|
|
5049
|
+
code,
|
|
5050
|
+
version,
|
|
5051
|
+
replyId,
|
|
5052
|
+
isBuiltIn,
|
|
5053
|
+
hasDirectUrl: Boolean(url)
|
|
5054
|
+
});
|
|
5055
|
+
if (!action) {
|
|
5056
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing action`, msg);
|
|
5057
|
+
return;
|
|
5058
|
+
}
|
|
5059
|
+
if (action === "GET_CRON_JOBS_BY_AGENT_ID") {
|
|
5060
|
+
const agentId = typeof msg.agent_id === "string" ? msg.agent_id : typeof msg.agentId === "string" ? msg.agentId : userId;
|
|
5061
|
+
if (!agentId) {
|
|
5062
|
+
this.reply(replyId, { success: false, message: "Missing agent_id parameter", action });
|
|
5063
|
+
return;
|
|
5064
|
+
}
|
|
5065
|
+
try {
|
|
5066
|
+
const data = readCronJobsByAgentId(agentId, defaultOpenclawSqlitePath(), (err) => {
|
|
5067
|
+
this.appendLogToFile("WARN", "Command", `GET_CRON_JOBS_BY_AGENT_ID sqlite lookup skipped`, err);
|
|
5068
|
+
});
|
|
5069
|
+
this.reply(replyId, { success: true, data, action });
|
|
5070
|
+
} catch (err) {
|
|
5071
|
+
this.appendLogToFile("ERROR", "Command", `GET_CRON_JOBS_BY_AGENT_ID threw`, err);
|
|
5072
|
+
this.reply(replyId, { success: false, message: err.message, action });
|
|
5073
|
+
}
|
|
5074
|
+
return;
|
|
5075
|
+
}
|
|
5076
|
+
if (!userId) {
|
|
5077
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing userId`, msg);
|
|
5078
|
+
return;
|
|
5079
|
+
}
|
|
5080
|
+
const safeCode = normalizeCommandCode(code);
|
|
5081
|
+
if (code !== void 0 && !safeCode) {
|
|
5082
|
+
this.reply(replyId, { success: false, message: `Invalid code: ${String(code)}`, action });
|
|
1856
5083
|
return;
|
|
1857
5084
|
}
|
|
1858
|
-
const safeCode = code ? path7.basename(code) : void 0;
|
|
1859
5085
|
const pureId = normalizeAssistantUserId(userId);
|
|
1860
5086
|
if (!pureId) {
|
|
1861
5087
|
this.reply(replyId, { success: false, message: `Invalid userId: ${userId}`, action });
|
|
1862
5088
|
return;
|
|
1863
5089
|
}
|
|
1864
|
-
const targetDir = path7.join(openclawHome(), `workspace-assistant-${pureId}`, "skills");
|
|
1865
5090
|
try {
|
|
1866
5091
|
if (action === "INSTALL_SKILL") {
|
|
1867
5092
|
if (!safeCode) throw new Error("Missing code parameter");
|
|
5093
|
+
const targetDir = await this.resolveRegularSkillTarget(userId);
|
|
1868
5094
|
console.log(`[skill-logger-plugin][WS] Executing INSTALL for user ${userId}, code: ${safeCode}`);
|
|
1869
5095
|
this.appendLogToFile("INFO", "Command", `INSTALL_SKILL received`, { userId, code: safeCode, version });
|
|
1870
5096
|
const result = await this.options.updater.manualInstall({
|
|
@@ -1872,21 +5098,24 @@ var GatewayWsClient = class {
|
|
|
1872
5098
|
url,
|
|
1873
5099
|
version,
|
|
1874
5100
|
force: force !== false,
|
|
1875
|
-
targetDir
|
|
5101
|
+
targetDir,
|
|
5102
|
+
trace: this.createInstallTrace({ action, replyId, userId, code: safeCode })
|
|
1876
5103
|
});
|
|
1877
5104
|
this.reply(replyId, { success: result.success, message: result.message, action });
|
|
1878
5105
|
} else if (action === "UNINSTALL_SKILL") {
|
|
1879
5106
|
if (!safeCode) throw new Error("Missing code parameter");
|
|
5107
|
+
const targetDir = await this.resolveRegularSkillTarget(userId);
|
|
1880
5108
|
console.log(`[skill-logger-plugin][WS] Executing UNINSTALL for user ${userId}, code: ${safeCode}`);
|
|
1881
5109
|
this.appendLogToFile("INFO", "Command", `UNINSTALL_SKILL received`, { userId, code: safeCode });
|
|
1882
|
-
const skillPath =
|
|
1883
|
-
await
|
|
5110
|
+
const skillPath = path9.join(targetDir, safeCode);
|
|
5111
|
+
await fs8.rm(skillPath, { recursive: true, force: true });
|
|
1884
5112
|
this.reply(replyId, { success: true, message: `Skill ${safeCode} removed`, action });
|
|
1885
5113
|
} else if (action === "LIST_SKILLS") {
|
|
5114
|
+
const targetDir = await this.resolveRegularSkillTarget(userId);
|
|
1886
5115
|
let list = [];
|
|
1887
5116
|
let targetDirExists = false;
|
|
1888
5117
|
try {
|
|
1889
|
-
const targetStat = await
|
|
5118
|
+
const targetStat = await fs8.stat(targetDir);
|
|
1890
5119
|
targetDirExists = targetStat.isDirectory();
|
|
1891
5120
|
} catch (err) {
|
|
1892
5121
|
if (err?.code !== "ENOENT") throw err;
|
|
@@ -1894,26 +5123,26 @@ var GatewayWsClient = class {
|
|
|
1894
5123
|
if (!targetDirExists) {
|
|
1895
5124
|
throw new Error(`Target skills directory does not exist: ${targetDir}`);
|
|
1896
5125
|
}
|
|
1897
|
-
const entries = await
|
|
5126
|
+
const entries = await fs8.readdir(targetDir, { withFileTypes: true });
|
|
1898
5127
|
const dirs = entries.filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith("."));
|
|
1899
5128
|
for (const e of dirs) {
|
|
1900
|
-
const skillDir =
|
|
1901
|
-
const skillMdPath =
|
|
5129
|
+
const skillDir = path9.join(targetDir, e.name);
|
|
5130
|
+
const skillMdPath = path9.join(skillDir, "SKILL.md");
|
|
1902
5131
|
try {
|
|
1903
|
-
const stat = await
|
|
5132
|
+
const stat = await fs8.stat(skillMdPath);
|
|
1904
5133
|
if (!stat.isFile()) continue;
|
|
1905
5134
|
} catch (err) {
|
|
1906
5135
|
continue;
|
|
1907
5136
|
}
|
|
1908
|
-
const metaPath =
|
|
5137
|
+
const metaPath = path9.join(skillDir, ".meta.json");
|
|
1909
5138
|
let isPlatform = false;
|
|
1910
|
-
let
|
|
5139
|
+
let isBuiltIn2 = e.isSymbolicLink();
|
|
1911
5140
|
let metaData = null;
|
|
1912
5141
|
let name = e.name;
|
|
1913
5142
|
let description = "";
|
|
1914
5143
|
let skillVersion = "";
|
|
1915
5144
|
try {
|
|
1916
|
-
const mdContent = await
|
|
5145
|
+
const mdContent = await fs8.readFile(skillMdPath, "utf8");
|
|
1917
5146
|
const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(mdContent)?.[1] ?? "";
|
|
1918
5147
|
const parsedName = /(^|\n)name:\s*(.+)/.exec(fm)?.[2]?.trim();
|
|
1919
5148
|
if (parsedName) name = parsedName;
|
|
@@ -1924,11 +5153,11 @@ var GatewayWsClient = class {
|
|
|
1924
5153
|
} catch (err) {
|
|
1925
5154
|
}
|
|
1926
5155
|
try {
|
|
1927
|
-
const metaContent = await
|
|
5156
|
+
const metaContent = await fs8.readFile(metaPath, "utf8");
|
|
1928
5157
|
const parsed = JSON.parse(metaContent);
|
|
1929
5158
|
if (parsed) {
|
|
1930
5159
|
if (parsed.ownerId === "CMS" || parsed.ownerId === "CMS_COMPAT") isPlatform = true;
|
|
1931
|
-
if (parsed.isBuiltIn === true || parsed.ownerId === "built-in")
|
|
5160
|
+
if (parsed.isBuiltIn === true || parsed.ownerId === "built-in") isBuiltIn2 = true;
|
|
1932
5161
|
metaData = parsed;
|
|
1933
5162
|
}
|
|
1934
5163
|
} catch (err) {
|
|
@@ -1939,7 +5168,7 @@ var GatewayWsClient = class {
|
|
|
1939
5168
|
list.push({
|
|
1940
5169
|
code: e.name,
|
|
1941
5170
|
isPlatform: true,
|
|
1942
|
-
isBuiltIn,
|
|
5171
|
+
isBuiltIn: isBuiltIn2,
|
|
1943
5172
|
version: skillVersion,
|
|
1944
5173
|
name,
|
|
1945
5174
|
description,
|
|
@@ -1949,7 +5178,7 @@ var GatewayWsClient = class {
|
|
|
1949
5178
|
list.push({
|
|
1950
5179
|
code: e.name,
|
|
1951
5180
|
isPlatform: false,
|
|
1952
|
-
isBuiltIn,
|
|
5181
|
+
isBuiltIn: isBuiltIn2,
|
|
1953
5182
|
version: skillVersion,
|
|
1954
5183
|
name,
|
|
1955
5184
|
description
|
|
@@ -1960,21 +5189,57 @@ var GatewayWsClient = class {
|
|
|
1960
5189
|
} else if (action === "UPDATE_SKILL") {
|
|
1961
5190
|
if (!safeCode) throw new Error("Missing code parameter");
|
|
1962
5191
|
const delayMs = Math.random() * 5e3;
|
|
5192
|
+
const syncBuiltInTemplate = shouldSyncBuiltInTemplate(action, isBuiltIn);
|
|
1963
5193
|
console.log(`[skill-logger-plugin][WS] Scheduled UPDATE for user ${userId}, code: ${safeCode} in ${Math.round(delayMs)}ms`);
|
|
1964
|
-
this.appendLogToFile("INFO", "Command", `Scheduled UPDATE_SKILL`, {
|
|
5194
|
+
this.appendLogToFile("INFO", "Command", `Scheduled UPDATE_SKILL`, {
|
|
5195
|
+
userId,
|
|
5196
|
+
code: safeCode,
|
|
5197
|
+
version,
|
|
5198
|
+
isBuiltIn,
|
|
5199
|
+
syncBuiltInTemplate,
|
|
5200
|
+
delayMs: Math.round(delayMs)
|
|
5201
|
+
});
|
|
1965
5202
|
setTimeout(async () => {
|
|
1966
5203
|
try {
|
|
1967
|
-
await this.
|
|
5204
|
+
const targetDir = await this.resolveRegularSkillTarget(userId);
|
|
5205
|
+
const additionalTargetDirs = syncBuiltInTemplate ? [path9.join(openclawHome(), "workspace-xgjk-assistant-template", "skills")] : [];
|
|
5206
|
+
const userSkillRoot = await findInstalledExpertSkillsRoot(openclawHome(), pureId, safeCode);
|
|
5207
|
+
if (userSkillRoot) additionalTargetDirs.push(userSkillRoot);
|
|
5208
|
+
const result = await this.options.updater.manualInstall({
|
|
1968
5209
|
code: safeCode,
|
|
1969
5210
|
url,
|
|
1970
5211
|
version,
|
|
1971
5212
|
force: true,
|
|
1972
|
-
targetDir
|
|
5213
|
+
targetDir,
|
|
5214
|
+
additionalTargetDirs,
|
|
5215
|
+
trace: this.createInstallTrace({
|
|
5216
|
+
action,
|
|
5217
|
+
replyId,
|
|
5218
|
+
userId,
|
|
5219
|
+
code: safeCode,
|
|
5220
|
+
isBuiltIn,
|
|
5221
|
+
syncBuiltInTemplate
|
|
5222
|
+
})
|
|
5223
|
+
});
|
|
5224
|
+
this.appendLogToFile(result.success ? "INFO" : "ERROR", "Command", `UPDATE_SKILL completed`, {
|
|
5225
|
+
userId,
|
|
5226
|
+
code: safeCode,
|
|
5227
|
+
replyId,
|
|
5228
|
+
success: result.success,
|
|
5229
|
+
message: result.message,
|
|
5230
|
+
syncBuiltInTemplate
|
|
1973
5231
|
});
|
|
1974
5232
|
if (replyId) {
|
|
1975
|
-
this.reply(replyId, { success:
|
|
5233
|
+
this.reply(replyId, { success: result.success, message: result.message, action });
|
|
1976
5234
|
}
|
|
1977
5235
|
} catch (e) {
|
|
5236
|
+
this.appendLogToFile("ERROR", "Command", `UPDATE_SKILL threw`, {
|
|
5237
|
+
userId,
|
|
5238
|
+
code: safeCode,
|
|
5239
|
+
replyId,
|
|
5240
|
+
message: e?.message || String(e),
|
|
5241
|
+
stack: e?.stack
|
|
5242
|
+
});
|
|
1978
5243
|
if (replyId) this.reply(replyId, { success: false, message: e.message, action });
|
|
1979
5244
|
}
|
|
1980
5245
|
}, delayMs);
|
|
@@ -1983,28 +5248,52 @@ var GatewayWsClient = class {
|
|
|
1983
5248
|
const { name, version: version2, downloadUrl, skills } = msg;
|
|
1984
5249
|
console.log(`[skill-logger-plugin][WS] Executing INSTALL_EXPERT for user ${userId}, code: ${safeCode}`);
|
|
1985
5250
|
this.appendLogToFile("INFO", "Command", `INSTALL_EXPERT received`, { userId, code: safeCode, version: version2, downloadUrl });
|
|
1986
|
-
const userSkillRoot =
|
|
1987
|
-
const expertTarget =
|
|
1988
|
-
|
|
1989
|
-
const
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
5251
|
+
const userSkillRoot = path9.join(openclawHome(), `workspace-assistant-${pureId}`, ".user");
|
|
5252
|
+
const expertTarget = path9.join(userSkillRoot, "experts", safeCode);
|
|
5253
|
+
let skipInstall = false;
|
|
5254
|
+
const metaPath = path9.join(expertTarget, ".meta.json");
|
|
5255
|
+
try {
|
|
5256
|
+
const raw = await fs8.readFile(metaPath, "utf-8");
|
|
5257
|
+
const existing = JSON.parse(raw);
|
|
5258
|
+
if (existing.version && existing.version === (version2 || "1.0.0")) {
|
|
5259
|
+
skipInstall = true;
|
|
5260
|
+
}
|
|
5261
|
+
} catch {
|
|
5262
|
+
}
|
|
5263
|
+
if (!skipInstall) {
|
|
5264
|
+
await fs8.mkdir(path9.dirname(expertTarget), { recursive: true });
|
|
5265
|
+
const expertResult = await this.options.updater.installExpertZipFromUrl(downloadUrl, expertTarget);
|
|
5266
|
+
if (!expertResult.success) {
|
|
5267
|
+
throw new Error(`\u4E13\u5BB6\u5B89\u88C5\u5931\u8D25: ${expertResult.message}`);
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
const meta = { code: safeCode, name, version: version2 || "1.0.0", installedAt: Date.now() };
|
|
5271
|
+
await fs8.writeFile(metaPath, JSON.stringify(meta, null, 2));
|
|
5272
|
+
const skillTargetRoot = path9.join(userSkillRoot, "skills");
|
|
5273
|
+
await fs8.mkdir(skillTargetRoot, { recursive: true });
|
|
1995
5274
|
const skillResults = [];
|
|
1996
5275
|
if (Array.isArray(skills)) {
|
|
1997
5276
|
for (const sk of skills) {
|
|
1998
|
-
|
|
1999
|
-
|
|
5277
|
+
const skillCode = normalizeCommandCode(sk?.code);
|
|
5278
|
+
if (!skillCode) {
|
|
5279
|
+
skillResults.push(`${String(sk?.code || "unknown")}: \u5931\u8D25 - \u975E\u6CD5\u7684 Skill code`);
|
|
5280
|
+
continue;
|
|
5281
|
+
}
|
|
5282
|
+
if (!sk.downloadUrl) {
|
|
5283
|
+
skillResults.push(`${skillCode}: \u5931\u8D25 - \u7F3A\u5C11\u4E0B\u8F7D\u5730\u5740`);
|
|
2000
5284
|
continue;
|
|
2001
5285
|
}
|
|
2002
5286
|
try {
|
|
2003
|
-
const
|
|
2004
|
-
|
|
2005
|
-
|
|
5287
|
+
const result = await this.options.updater.manualInstall({
|
|
5288
|
+
code: skillCode,
|
|
5289
|
+
url: sk.downloadUrl,
|
|
5290
|
+
version: sk.version,
|
|
5291
|
+
force: true,
|
|
5292
|
+
targetDir: skillTargetRoot
|
|
5293
|
+
});
|
|
5294
|
+
skillResults.push(`${skillCode}: ${result.success ? "\u6210\u529F" : "\u5931\u8D25 - " + result.message}`);
|
|
2006
5295
|
} catch (e) {
|
|
2007
|
-
skillResults.push(`${
|
|
5296
|
+
skillResults.push(`${skillCode}: \u5931\u8D25 - ${e.message}`);
|
|
2008
5297
|
}
|
|
2009
5298
|
}
|
|
2010
5299
|
}
|
|
@@ -2014,48 +5303,42 @@ var GatewayWsClient = class {
|
|
|
2014
5303
|
action,
|
|
2015
5304
|
data: { expertCode: safeCode, skills: skillResults }
|
|
2016
5305
|
});
|
|
2017
|
-
} else if (action === "
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
5306
|
+
} else if (action === "UNINSTALL_EXPERT") {
|
|
5307
|
+
if (!safeCode) throw new Error("Missing code parameter");
|
|
5308
|
+
console.log(`[skill-logger-plugin][WS] Executing UNINSTALL_EXPERT for user ${userId}, code: ${safeCode}`);
|
|
5309
|
+
this.appendLogToFile("INFO", "Command", `UNINSTALL_EXPERT received`, { userId, code: safeCode });
|
|
5310
|
+
const expertPath = path9.join(openclawHome(), `workspace-assistant-${pureId}`, ".user", "experts", safeCode);
|
|
5311
|
+
await fs8.rm(expertPath, { recursive: true, force: true });
|
|
5312
|
+
this.reply(replyId, { success: true, message: `\u4E13\u5BB6 ${safeCode} \u5DF2\u5378\u8F7D`, action });
|
|
5313
|
+
} else if (action === "LIST_EXPERTS") {
|
|
5314
|
+
console.log(`[skill-logger-plugin][WS] Executing LIST_EXPERTS for user ${userId}`);
|
|
5315
|
+
this.appendLogToFile("INFO", "Command", `LIST_EXPERTS received`, { userId });
|
|
5316
|
+
const expertsDir = path9.join(openclawHome(), `workspace-assistant-${pureId}`, ".user", "experts");
|
|
5317
|
+
const list = [];
|
|
2023
5318
|
try {
|
|
2024
|
-
const stat = await
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
continue;
|
|
2042
|
-
}
|
|
2043
|
-
if (currentExpert) {
|
|
2044
|
-
const nameMatch = line.match(/^\s*name:\s*(.+)$/);
|
|
2045
|
-
if (nameMatch) {
|
|
2046
|
-
currentExpert.name = nameMatch[1].trim();
|
|
2047
|
-
}
|
|
2048
|
-
const descMatch = line.match(/^\s*description:\s*(.+)$/);
|
|
2049
|
-
if (descMatch) {
|
|
2050
|
-
currentExpert.description = descMatch[1].trim();
|
|
5319
|
+
const stat = await fs8.stat(expertsDir);
|
|
5320
|
+
if (stat.isDirectory()) {
|
|
5321
|
+
const entries = await fs8.readdir(expertsDir, { withFileTypes: true });
|
|
5322
|
+
for (const e of entries) {
|
|
5323
|
+
if (!e.isDirectory()) continue;
|
|
5324
|
+
const metaPath = path9.join(expertsDir, e.name, ".meta.json");
|
|
5325
|
+
try {
|
|
5326
|
+
const raw = await fs8.readFile(metaPath, "utf-8");
|
|
5327
|
+
const meta = JSON.parse(raw);
|
|
5328
|
+
list.push({
|
|
5329
|
+
code: meta.code || e.name,
|
|
5330
|
+
name: meta.name || e.name,
|
|
5331
|
+
version: meta.version || "",
|
|
5332
|
+
installedAt: meta.installedAt
|
|
5333
|
+
});
|
|
5334
|
+
} catch {
|
|
5335
|
+
list.push({ code: e.name, name: e.name, version: "" });
|
|
2051
5336
|
}
|
|
2052
5337
|
}
|
|
2053
5338
|
}
|
|
2054
|
-
|
|
2055
|
-
this.reply(replyId, { success: true, data: expertsList, action });
|
|
2056
|
-
} else {
|
|
2057
|
-
this.reply(replyId, { success: false, message: `\u672A\u627E\u5230\u7528\u6237\u6280\u80FD\u914D\u7F6E\u6587\u4EF6\uFF0C\u53EF\u80FD\u5C1A\u672A\u6CE8\u518C\u6216\u6587\u4EF6\u5DF2\u4E22\u5931`, action });
|
|
5339
|
+
} catch {
|
|
2058
5340
|
}
|
|
5341
|
+
this.reply(replyId, { success: true, data: list, action });
|
|
2059
5342
|
} else {
|
|
2060
5343
|
console.warn(`[skill-logger-plugin][WS] Unknown action: ${action}`);
|
|
2061
5344
|
this.appendLogToFile("WARN", "Command", `Unknown action: ${action}`);
|
|
@@ -2072,7 +5355,13 @@ var GatewayWsClient = class {
|
|
|
2072
5355
|
this.appendLogToFile("WARN", "Command", `Cannot reply: WS closed or missing replyId`, { replyId });
|
|
2073
5356
|
return;
|
|
2074
5357
|
}
|
|
2075
|
-
this.ws.send(JSON.stringify({ type: "REPLY", replyId, ...payload }))
|
|
5358
|
+
this.ws.send(JSON.stringify({ type: "REPLY", replyId, ...payload }), (err) => {
|
|
5359
|
+
if (err) {
|
|
5360
|
+
this.appendLogToFile("ERROR", "Command", `Reply send failed`, { replyId, message: err.message });
|
|
5361
|
+
return;
|
|
5362
|
+
}
|
|
5363
|
+
this.appendLogToFile("INFO", "Command", `Reply sent`, { replyId });
|
|
5364
|
+
});
|
|
2076
5365
|
}
|
|
2077
5366
|
destroy() {
|
|
2078
5367
|
this.isDestroyed = true;
|
|
@@ -2088,8 +5377,8 @@ var GatewayWsClient = class {
|
|
|
2088
5377
|
};
|
|
2089
5378
|
|
|
2090
5379
|
// src/hooks.ts
|
|
2091
|
-
import
|
|
2092
|
-
import { randomUUID as
|
|
5380
|
+
import path10 from "node:path";
|
|
5381
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
2093
5382
|
var PENDING_TTL_MS = 30 * 60 * 1e3;
|
|
2094
5383
|
var PENDING_MAX = 5e3;
|
|
2095
5384
|
function toMySQLDateTime(d) {
|
|
@@ -2097,7 +5386,7 @@ function toMySQLDateTime(d) {
|
|
|
2097
5386
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
2098
5387
|
}
|
|
2099
5388
|
function isSkillMdReadPath(filePath) {
|
|
2100
|
-
return
|
|
5389
|
+
return path10.basename(filePath) === "SKILL.md";
|
|
2101
5390
|
}
|
|
2102
5391
|
function extractAppKey(event, ctx) {
|
|
2103
5392
|
try {
|
|
@@ -2207,7 +5496,7 @@ var Hooks = class {
|
|
|
2207
5496
|
}
|
|
2208
5497
|
buildPendingEvent(p, status, error, durationMs, appKey) {
|
|
2209
5498
|
return {
|
|
2210
|
-
event_id:
|
|
5499
|
+
event_id: randomUUID3(),
|
|
2211
5500
|
event_type: "function_call",
|
|
2212
5501
|
skill_name: p.skillName,
|
|
2213
5502
|
skill_version: p.skillVersion,
|
|
@@ -2237,27 +5526,6 @@ var Hooks = class {
|
|
|
2237
5526
|
this.sessionAppKeys.set(sk, rawAppKey);
|
|
2238
5527
|
}
|
|
2239
5528
|
}
|
|
2240
|
-
onManualErrorRecord(args, ctx) {
|
|
2241
|
-
const sk = this.sessionKeyOf(ctx);
|
|
2242
|
-
let appKey = sk ? this.sessionAppKeys.get(sk) : void 0;
|
|
2243
|
-
this.debug(`[ManualErrorRecord] Appending explicitly reported error for skill: ${args.skill_name}`);
|
|
2244
|
-
this.emit({
|
|
2245
|
-
event_id: randomUUID2(),
|
|
2246
|
-
event_type: "function_call",
|
|
2247
|
-
skill_name: args.skill_name || "unknown_skill",
|
|
2248
|
-
skill_version: this.configSync.getVersion(args.skill_name),
|
|
2249
|
-
function_name: args.tool_name || "unknown_tool",
|
|
2250
|
-
invoke_tool: "report_skill_error",
|
|
2251
|
-
args: args.input_args ? { raw_args: args.input_args } : void 0,
|
|
2252
|
-
status: "error",
|
|
2253
|
-
error_message: args.error_message,
|
|
2254
|
-
app_key: appKey || "",
|
|
2255
|
-
session_id: sk,
|
|
2256
|
-
agent_id: ctx.agentId,
|
|
2257
|
-
run_id: ctx.runId,
|
|
2258
|
-
called_at: toMySQLDateTime(/* @__PURE__ */ new Date())
|
|
2259
|
-
});
|
|
2260
|
-
}
|
|
2261
5529
|
onBeforeToolCall(event, ctx) {
|
|
2262
5530
|
try {
|
|
2263
5531
|
this.sweepStalePending();
|
|
@@ -2298,8 +5566,8 @@ var Hooks = class {
|
|
|
2298
5566
|
if (toolName === "read") {
|
|
2299
5567
|
const filePath = params.path ?? params.file_path ?? "";
|
|
2300
5568
|
if (!isSkillMdReadPath(filePath)) return;
|
|
2301
|
-
const rootDir =
|
|
2302
|
-
const skillName = this.configSync.resolveSkillName(rootDir) ||
|
|
5569
|
+
const rootDir = path10.dirname(filePath);
|
|
5570
|
+
const skillName = this.configSync.resolveSkillName(rootDir) || path10.basename(rootDir);
|
|
2303
5571
|
if (!skillName) return;
|
|
2304
5572
|
this.debug(`Intercepted 'read' for SKILL.md. Attributed to skill: ${skillName}`);
|
|
2305
5573
|
this.recordTrigger(skillName, "inline", "read", ctx, appKey);
|
|
@@ -2384,7 +5652,7 @@ var Hooks = class {
|
|
|
2384
5652
|
/** 记 skill 触发事件 + 标记激活 + 懒拉配置。 */
|
|
2385
5653
|
recordTrigger(skillName, invokeMode, invokeTool, ctx, appKey) {
|
|
2386
5654
|
this.emit({
|
|
2387
|
-
event_id:
|
|
5655
|
+
event_id: randomUUID3(),
|
|
2388
5656
|
event_type: "skill_trigger",
|
|
2389
5657
|
skill_name: skillName,
|
|
2390
5658
|
skill_version: this.configSync.getVersion(skillName),
|
|
@@ -2404,7 +5672,7 @@ var Hooks = class {
|
|
|
2404
5672
|
}
|
|
2405
5673
|
buildFunctionCall(res, command, invokeTool, status, error, durationMs, ctx, appKey) {
|
|
2406
5674
|
return {
|
|
2407
|
-
event_id:
|
|
5675
|
+
event_id: randomUUID3(),
|
|
2408
5676
|
event_type: "function_call",
|
|
2409
5677
|
skill_name: res.skillName,
|
|
2410
5678
|
skill_version: res.skillVersion,
|
|
@@ -2446,7 +5714,7 @@ var Hooks = class {
|
|
|
2446
5714
|
return;
|
|
2447
5715
|
}
|
|
2448
5716
|
this.emit({
|
|
2449
|
-
event_id:
|
|
5717
|
+
event_id: randomUUID3(),
|
|
2450
5718
|
event_type: "function_call",
|
|
2451
5719
|
skill_name: skillName,
|
|
2452
5720
|
match_type: void 0,
|
|
@@ -2499,9 +5767,9 @@ var definition = {
|
|
|
2499
5767
|
register(api) {
|
|
2500
5768
|
let pkgVersion = "unknown";
|
|
2501
5769
|
try {
|
|
2502
|
-
const dir =
|
|
2503
|
-
const pkgPath =
|
|
2504
|
-
const pkg = JSON.parse(
|
|
5770
|
+
const dir = path11.dirname(fileURLToPath2(import.meta.url));
|
|
5771
|
+
const pkgPath = path11.join(dir, "..", "package.json");
|
|
5772
|
+
const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
|
|
2505
5773
|
if (pkg.version) pkgVersion = pkg.version;
|
|
2506
5774
|
} catch {
|
|
2507
5775
|
}
|
|
@@ -2518,34 +5786,25 @@ var definition = {
|
|
|
2518
5786
|
const configSync = new ConfigSync({ paths, getConfig, updater });
|
|
2519
5787
|
const reporter = new Reporter({ paths, getConfig });
|
|
2520
5788
|
const hooks = new Hooks(reporter, configSync, activeSkills, getConfig);
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
properties: {
|
|
2529
|
-
skill_name: { type: "string", description: "\u53D1\u751F\u9519\u8BEF\u7684\u6280\u80FD\u540D\u79F0" },
|
|
2530
|
-
tool_name: { type: "string", description: "\u53D1\u751F\u9519\u8BEF\u7684\u5177\u4F53\u5DE5\u5177\u540D\u79F0" },
|
|
2531
|
-
error_message: { type: "string", description: "\u5177\u4F53\u7684\u62A5\u9519\u539F\u56E0\u6216\u5F02\u5E38\u6808" },
|
|
2532
|
-
input_args: { type: "string", description: "\u5F53\u65F6\u4F20\u5165\u8BE5\u5DE5\u5177\u7684\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
|
|
2533
|
-
},
|
|
2534
|
-
required: ["skill_name", "tool_name", "error_message"]
|
|
2535
|
-
},
|
|
2536
|
-
execute: async (args) => {
|
|
2537
|
-
hooks.onManualErrorRecord(args, ctx);
|
|
2538
|
-
return { content: [{ type: "text", text: "\u5DF2\u6210\u529F\u4E0A\u62A5\u9519\u8BEF\u8BB0\u5F55\u3002" }] };
|
|
2539
|
-
}
|
|
2540
|
-
}), { name: "report_skill_error" });
|
|
2541
|
-
} catch (err) {
|
|
2542
|
-
if (typeof api.logger?.error === "function") {
|
|
2543
|
-
api.logger.error("[skill-logger-plugin] Failed to register or inject 'report_skill_error' tool:", err);
|
|
2544
|
-
} else {
|
|
2545
|
-
console.error("[skill-logger-plugin] Failed to register or inject 'report_skill_error' tool:", err);
|
|
5789
|
+
let expertSkillLayoutRepair;
|
|
5790
|
+
const repairExpertSkillLayouts = () => {
|
|
5791
|
+
if (expertSkillLayoutRepair) return expertSkillLayoutRepair;
|
|
5792
|
+
expertSkillLayoutRepair = (async () => {
|
|
5793
|
+
const result = await repairNestedExpertSkillLayouts(openclawHome());
|
|
5794
|
+
if (result.repaired.length > 0) {
|
|
5795
|
+
console.log(`[skill-logger-plugin] \u5DF2\u4FEE\u590D ${result.repaired.length} \u4E2A\u4E13\u5BB6 Skill \u5D4C\u5957\u76EE\u5F55`);
|
|
2546
5796
|
}
|
|
2547
|
-
|
|
2548
|
-
|
|
5797
|
+
for (const skippedPath of result.skipped) {
|
|
5798
|
+
console.warn(`[skill-logger-plugin] \u4E13\u5BB6 Skill \u5D4C\u5957\u76EE\u5F55\u7248\u672C\u65E0\u6CD5\u5B89\u5168\u63D0\u5347\uFF0C\u5DF2\u4FDD\u7559\u73B0\u573A: ${skippedPath}`);
|
|
5799
|
+
}
|
|
5800
|
+
for (const error of result.errors) {
|
|
5801
|
+
console.warn(`[skill-logger-plugin] \u4FEE\u590D\u4E13\u5BB6 Skill \u76EE\u5F55\u5931\u8D25: ${error.path}`, error.message);
|
|
5802
|
+
}
|
|
5803
|
+
})().finally(() => {
|
|
5804
|
+
expertSkillLayoutRepair = void 0;
|
|
5805
|
+
});
|
|
5806
|
+
return expertSkillLayoutRepair;
|
|
5807
|
+
};
|
|
2549
5808
|
let reconcileTimer;
|
|
2550
5809
|
const sessionUpdatedSkills = /* @__PURE__ */ new Set();
|
|
2551
5810
|
api.on("message_received", (event, ctx) => {
|
|
@@ -2553,10 +5812,9 @@ var definition = {
|
|
|
2553
5812
|
hooks.onMessageReceived(event, ctx);
|
|
2554
5813
|
});
|
|
2555
5814
|
api.on("before_prompt_build", () => {
|
|
2556
|
-
let appendStr = "
|
|
5815
|
+
let appendStr = "";
|
|
2557
5816
|
if (sessionUpdatedSkills.size > 0) {
|
|
2558
|
-
appendStr
|
|
2559
|
-
\u3010\u7CFB\u7EDF\u73AF\u5883\u5B9E\u65F6\u901A\u77E5\u3011\uFF1A\u5728\u5F53\u524D\u5BF9\u8BDD\u671F\u95F4\uFF0C\u4EE5\u4E0B\u6280\u80FD\u5DF2\u88AB\u66F4\u65B0\u6216\u91CD\u88C5\uFF1A[${Array.from(sessionUpdatedSkills).join(", ")}]\u3002\u5982\u679C\u4F60\u4E4B\u524D\u8C03\u7528\u5B83\u9047\u5230\u4E86\u62A5\u9519\uFF0C\u8BF7\u7ACB\u5373\u629B\u5F03\u65E7\u7684\u7ECF\u9A8C\uFF0C\u91CD\u65B0\u9605\u8BFB\u5B83\u7684\u8BF4\u660E\u5E76\u4EE5\u6700\u65B0\u7ED3\u679C\u4E3A\u51C6\uFF01`;
|
|
5817
|
+
appendStr = `\u3010\u7CFB\u7EDF\u73AF\u5883\u5B9E\u65F6\u901A\u77E5\u3011\uFF1A\u5728\u5F53\u524D\u5BF9\u8BDD\u671F\u95F4\uFF0C\u4EE5\u4E0B\u6280\u80FD\u5DF2\u88AB\u66F4\u65B0\u6216\u91CD\u88C5\uFF1A[${Array.from(sessionUpdatedSkills).join(", ")}]\u3002\u5982\u679C\u4F60\u4E4B\u524D\u8C03\u7528\u5B83\u9047\u5230\u4E86\u62A5\u9519\uFF0C\u8BF7\u7ACB\u5373\u629B\u5F03\u65E7\u7684\u7ECF\u9A8C\uFF0C\u91CD\u65B0\u9605\u8BFB\u5B83\u7684\u8BF4\u660E\u5E76\u4EE5\u6700\u65B0\u7ED3\u679C\u4E3A\u51C6\uFF01`;
|
|
2560
5818
|
}
|
|
2561
5819
|
return { appendSystemContext: appendStr.trim() };
|
|
2562
5820
|
});
|
|
@@ -2597,9 +5855,8 @@ var definition = {
|
|
|
2597
5855
|
enableFileLog: currentConfig2.enableFileLog
|
|
2598
5856
|
// 将日志开关透传给客户端模块
|
|
2599
5857
|
});
|
|
2600
|
-
wsClient.connect();
|
|
2601
5858
|
}
|
|
2602
|
-
void configSync.load().then(() => configSync.reconcile()).catch((err) => console.warn("[skill-logger-plugin] \u542F\u52A8\u521D\u59CB\u5316\u5F02\u5E38", err));
|
|
5859
|
+
void repairExpertSkillLayouts().then(() => wsClient?.connect()).then(() => configSync.load()).then(() => configSync.reconcile()).catch((err) => console.warn("[skill-logger-plugin] \u542F\u52A8\u521D\u59CB\u5316\u5F02\u5E38", err));
|
|
2603
5860
|
reporter.startTimer();
|
|
2604
5861
|
if (!reconcileTimer) {
|
|
2605
5862
|
reconcileTimer = setInterval(() => void configSync.reconcile(), RECONCILE_INTERVAL_MS);
|