@spzhongwin/skill-logger-plugin 1.0.16 → 1.0.18
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 +2902 -281
- 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 +263 -158
- package/src/ws-client.ts +936 -805
- package/test-ws.ts +17 -17
- package/tsconfig.json +18 -18
package/dist/index.js
CHANGED
|
@@ -1,6 +1,2097 @@
|
|
|
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/fileSystem.js
|
|
34
|
+
var require_fileSystem = __commonJS({
|
|
35
|
+
"../../node_modules/adm-zip/util/fileSystem.js"(exports) {
|
|
36
|
+
exports.require = function() {
|
|
37
|
+
var fs10 = __require("fs");
|
|
38
|
+
if (process.versions["electron"]) {
|
|
39
|
+
try {
|
|
40
|
+
originalFs = __require("original-fs");
|
|
41
|
+
if (Object.keys(originalFs).length > 0) {
|
|
42
|
+
fs10 = originalFs;
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return fs10;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// ../../node_modules/adm-zip/util/constants.js
|
|
53
|
+
var require_constants = __commonJS({
|
|
54
|
+
"../../node_modules/adm-zip/util/constants.js"(exports, module) {
|
|
55
|
+
module.exports = {
|
|
56
|
+
/* The local file header */
|
|
57
|
+
LOCHDR: 30,
|
|
58
|
+
// LOC header size
|
|
59
|
+
LOCSIG: 67324752,
|
|
60
|
+
// "PK\003\004"
|
|
61
|
+
LOCVER: 4,
|
|
62
|
+
// version needed to extract
|
|
63
|
+
LOCFLG: 6,
|
|
64
|
+
// general purpose bit flag
|
|
65
|
+
LOCHOW: 8,
|
|
66
|
+
// compression method
|
|
67
|
+
LOCTIM: 10,
|
|
68
|
+
// modification time (2 bytes time, 2 bytes date)
|
|
69
|
+
LOCCRC: 14,
|
|
70
|
+
// uncompressed file crc-32 value
|
|
71
|
+
LOCSIZ: 18,
|
|
72
|
+
// compressed size
|
|
73
|
+
LOCLEN: 22,
|
|
74
|
+
// uncompressed size
|
|
75
|
+
LOCNAM: 26,
|
|
76
|
+
// filename length
|
|
77
|
+
LOCEXT: 28,
|
|
78
|
+
// extra field length
|
|
79
|
+
/* The Data descriptor */
|
|
80
|
+
EXTSIG: 134695760,
|
|
81
|
+
// "PK\007\008"
|
|
82
|
+
EXTHDR: 16,
|
|
83
|
+
// EXT header size
|
|
84
|
+
EXTCRC: 4,
|
|
85
|
+
// uncompressed file crc-32 value
|
|
86
|
+
EXTSIZ: 8,
|
|
87
|
+
// compressed size
|
|
88
|
+
EXTLEN: 12,
|
|
89
|
+
// uncompressed size
|
|
90
|
+
/* The central directory file header */
|
|
91
|
+
CENHDR: 46,
|
|
92
|
+
// CEN header size
|
|
93
|
+
CENSIG: 33639248,
|
|
94
|
+
// "PK\001\002"
|
|
95
|
+
CENVEM: 4,
|
|
96
|
+
// version made by
|
|
97
|
+
CENVER: 6,
|
|
98
|
+
// version needed to extract
|
|
99
|
+
CENFLG: 8,
|
|
100
|
+
// encrypt, decrypt flags
|
|
101
|
+
CENHOW: 10,
|
|
102
|
+
// compression method
|
|
103
|
+
CENTIM: 12,
|
|
104
|
+
// modification time (2 bytes time, 2 bytes date)
|
|
105
|
+
CENCRC: 16,
|
|
106
|
+
// uncompressed file crc-32 value
|
|
107
|
+
CENSIZ: 20,
|
|
108
|
+
// compressed size
|
|
109
|
+
CENLEN: 24,
|
|
110
|
+
// uncompressed size
|
|
111
|
+
CENNAM: 28,
|
|
112
|
+
// filename length
|
|
113
|
+
CENEXT: 30,
|
|
114
|
+
// extra field length
|
|
115
|
+
CENCOM: 32,
|
|
116
|
+
// file comment length
|
|
117
|
+
CENDSK: 34,
|
|
118
|
+
// volume number start
|
|
119
|
+
CENATT: 36,
|
|
120
|
+
// internal file attributes
|
|
121
|
+
CENATX: 38,
|
|
122
|
+
// external file attributes (host system dependent)
|
|
123
|
+
CENOFF: 42,
|
|
124
|
+
// LOC header offset
|
|
125
|
+
/* The entries in the end of central directory */
|
|
126
|
+
ENDHDR: 22,
|
|
127
|
+
// END header size
|
|
128
|
+
ENDSIG: 101010256,
|
|
129
|
+
// "PK\005\006"
|
|
130
|
+
ENDSUB: 8,
|
|
131
|
+
// number of entries on this disk
|
|
132
|
+
ENDTOT: 10,
|
|
133
|
+
// total number of entries
|
|
134
|
+
ENDSIZ: 12,
|
|
135
|
+
// central directory size in bytes
|
|
136
|
+
ENDOFF: 16,
|
|
137
|
+
// offset of first CEN header
|
|
138
|
+
ENDCOM: 20,
|
|
139
|
+
// zip file comment length
|
|
140
|
+
END64HDR: 20,
|
|
141
|
+
// zip64 END header size
|
|
142
|
+
END64SIG: 117853008,
|
|
143
|
+
// zip64 Locator signature, "PK\006\007"
|
|
144
|
+
END64START: 4,
|
|
145
|
+
// number of the disk with the start of the zip64
|
|
146
|
+
END64OFF: 8,
|
|
147
|
+
// relative offset of the zip64 end of central directory
|
|
148
|
+
END64NUMDISKS: 16,
|
|
149
|
+
// total number of disks
|
|
150
|
+
ZIP64SIG: 101075792,
|
|
151
|
+
// zip64 signature, "PK\006\006"
|
|
152
|
+
ZIP64HDR: 56,
|
|
153
|
+
// zip64 record minimum size
|
|
154
|
+
ZIP64LEAD: 12,
|
|
155
|
+
// leading bytes at the start of the record, not counted by the value stored in ZIP64SIZE
|
|
156
|
+
ZIP64SIZE: 4,
|
|
157
|
+
// zip64 size of the central directory record
|
|
158
|
+
ZIP64VEM: 12,
|
|
159
|
+
// zip64 version made by
|
|
160
|
+
ZIP64VER: 14,
|
|
161
|
+
// zip64 version needed to extract
|
|
162
|
+
ZIP64DSK: 16,
|
|
163
|
+
// zip64 number of this disk
|
|
164
|
+
ZIP64DSKDIR: 20,
|
|
165
|
+
// number of the disk with the start of the record directory
|
|
166
|
+
ZIP64SUB: 24,
|
|
167
|
+
// number of entries on this disk
|
|
168
|
+
ZIP64TOT: 32,
|
|
169
|
+
// total number of entries
|
|
170
|
+
ZIP64SIZB: 40,
|
|
171
|
+
// zip64 central directory size in bytes
|
|
172
|
+
ZIP64OFF: 48,
|
|
173
|
+
// offset of start of central directory with respect to the starting disk number
|
|
174
|
+
ZIP64EXTRA: 56,
|
|
175
|
+
// extensible data sector
|
|
176
|
+
/* Compression methods */
|
|
177
|
+
STORED: 0,
|
|
178
|
+
// no compression
|
|
179
|
+
SHRUNK: 1,
|
|
180
|
+
// shrunk
|
|
181
|
+
REDUCED1: 2,
|
|
182
|
+
// reduced with compression factor 1
|
|
183
|
+
REDUCED2: 3,
|
|
184
|
+
// reduced with compression factor 2
|
|
185
|
+
REDUCED3: 4,
|
|
186
|
+
// reduced with compression factor 3
|
|
187
|
+
REDUCED4: 5,
|
|
188
|
+
// reduced with compression factor 4
|
|
189
|
+
IMPLODED: 6,
|
|
190
|
+
// imploded
|
|
191
|
+
// 7 reserved
|
|
192
|
+
DEFLATED: 8,
|
|
193
|
+
// deflated
|
|
194
|
+
ENHANCED_DEFLATED: 9,
|
|
195
|
+
// enhanced deflated
|
|
196
|
+
PKWARE: 10,
|
|
197
|
+
// PKWare DCL imploded
|
|
198
|
+
// 11 reserved
|
|
199
|
+
BZIP2: 12,
|
|
200
|
+
// compressed using BZIP2
|
|
201
|
+
// 13 reserved
|
|
202
|
+
LZMA: 14,
|
|
203
|
+
// LZMA
|
|
204
|
+
// 15-17 reserved
|
|
205
|
+
IBM_TERSE: 18,
|
|
206
|
+
// compressed using IBM TERSE
|
|
207
|
+
IBM_LZ77: 19,
|
|
208
|
+
//IBM LZ77 z
|
|
209
|
+
/* General purpose bit flag */
|
|
210
|
+
FLG_ENC: 0,
|
|
211
|
+
// encripted file
|
|
212
|
+
FLG_COMP1: 1,
|
|
213
|
+
// compression option
|
|
214
|
+
FLG_COMP2: 2,
|
|
215
|
+
// compression option
|
|
216
|
+
FLG_DESC: 4,
|
|
217
|
+
// data descriptor
|
|
218
|
+
FLG_ENH: 8,
|
|
219
|
+
// enhanced deflation
|
|
220
|
+
FLG_STR: 16,
|
|
221
|
+
// strong encryption
|
|
222
|
+
FLG_LNG: 1024,
|
|
223
|
+
// language encoding
|
|
224
|
+
FLG_MSK: 4096,
|
|
225
|
+
// mask header values
|
|
226
|
+
/* Load type */
|
|
227
|
+
FILE: 0,
|
|
228
|
+
BUFFER: 1,
|
|
229
|
+
NONE: 2,
|
|
230
|
+
/* 4.5 Extensible data fields */
|
|
231
|
+
EF_ID: 0,
|
|
232
|
+
EF_SIZE: 2,
|
|
233
|
+
/* Header IDs */
|
|
234
|
+
ID_ZIP64: 1,
|
|
235
|
+
ID_AVINFO: 7,
|
|
236
|
+
ID_PFS: 8,
|
|
237
|
+
ID_OS2: 9,
|
|
238
|
+
ID_NTFS: 10,
|
|
239
|
+
ID_OPENVMS: 12,
|
|
240
|
+
ID_UNIX: 13,
|
|
241
|
+
ID_FORK: 14,
|
|
242
|
+
ID_PATCH: 15,
|
|
243
|
+
ID_X509_PKCS7: 20,
|
|
244
|
+
ID_X509_CERTID_F: 21,
|
|
245
|
+
ID_X509_CERTID_C: 22,
|
|
246
|
+
ID_STRONGENC: 23,
|
|
247
|
+
ID_RECORD_MGT: 24,
|
|
248
|
+
ID_X509_PKCS7_RL: 25,
|
|
249
|
+
ID_IBM1: 101,
|
|
250
|
+
ID_IBM2: 102,
|
|
251
|
+
ID_POSZIP: 18064,
|
|
252
|
+
EF_ZIP64_OR_32: 4294967295,
|
|
253
|
+
EF_ZIP64_OR_16: 65535,
|
|
254
|
+
EF_ZIP64_SUNCOMP: 0,
|
|
255
|
+
EF_ZIP64_SCOMP: 8,
|
|
256
|
+
EF_ZIP64_RHO: 16,
|
|
257
|
+
EF_ZIP64_DSN: 24
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// ../../node_modules/adm-zip/util/errors.js
|
|
263
|
+
var require_errors = __commonJS({
|
|
264
|
+
"../../node_modules/adm-zip/util/errors.js"(exports, module) {
|
|
265
|
+
module.exports = {
|
|
266
|
+
/* Header error messages */
|
|
267
|
+
"INVALID_LOC": "Invalid LOC header (bad signature)",
|
|
268
|
+
"INVALID_CEN": "Invalid CEN header (bad signature)",
|
|
269
|
+
"INVALID_END": "Invalid END header (bad signature)",
|
|
270
|
+
/* ZipEntry error messages*/
|
|
271
|
+
"NO_DATA": "Nothing to decompress",
|
|
272
|
+
"BAD_CRC": "CRC32 checksum failed",
|
|
273
|
+
"FILE_IN_THE_WAY": "There is a file in the way: %s",
|
|
274
|
+
"UNKNOWN_METHOD": "Invalid/unsupported compression method",
|
|
275
|
+
/* Inflater error messages */
|
|
276
|
+
"AVAIL_DATA": "inflate::Available inflate data did not terminate",
|
|
277
|
+
"INVALID_DISTANCE": "inflate::Invalid literal/length or distance code in fixed or dynamic block",
|
|
278
|
+
"TO_MANY_CODES": "inflate::Dynamic block code description: too many length or distance codes",
|
|
279
|
+
"INVALID_REPEAT_LEN": "inflate::Dynamic block code description: repeat more than specified lengths",
|
|
280
|
+
"INVALID_REPEAT_FIRST": "inflate::Dynamic block code description: repeat lengths with no first length",
|
|
281
|
+
"INCOMPLETE_CODES": "inflate::Dynamic block code description: code lengths codes incomplete",
|
|
282
|
+
"INVALID_DYN_DISTANCE": "inflate::Dynamic block code description: invalid distance code lengths",
|
|
283
|
+
"INVALID_CODES_LEN": "inflate::Dynamic block code description: invalid literal/length code lengths",
|
|
284
|
+
"INVALID_STORE_BLOCK": "inflate::Stored block length did not match one's complement",
|
|
285
|
+
"INVALID_BLOCK_TYPE": "inflate::Invalid block type (type == 3)",
|
|
286
|
+
/* ADM-ZIP error messages */
|
|
287
|
+
"CANT_EXTRACT_FILE": "Could not extract the file",
|
|
288
|
+
"CANT_OVERRIDE": "Target file already exists",
|
|
289
|
+
"NO_ZIP": "No zip file was loaded",
|
|
290
|
+
"NO_ENTRY": "Entry doesn't exist",
|
|
291
|
+
"DIRECTORY_CONTENT_ERROR": "A directory cannot have content",
|
|
292
|
+
"FILE_NOT_FOUND": "File not found: %s",
|
|
293
|
+
"NOT_IMPLEMENTED": "Not implemented",
|
|
294
|
+
"INVALID_FILENAME": "Invalid filename",
|
|
295
|
+
"INVALID_FORMAT": "Invalid or unsupported zip format. No END header found"
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// ../../node_modules/adm-zip/util/utils.js
|
|
301
|
+
var require_utils = __commonJS({
|
|
302
|
+
"../../node_modules/adm-zip/util/utils.js"(exports, module) {
|
|
303
|
+
var fs10 = require_fileSystem().require();
|
|
304
|
+
var pth = __require("path");
|
|
305
|
+
fs10.existsSync = fs10.existsSync || pth.existsSync;
|
|
306
|
+
module.exports = (function() {
|
|
307
|
+
var crcTable = [], Constants = require_constants(), Errors = require_errors(), PATH_SEPARATOR = pth.sep;
|
|
308
|
+
function mkdirSync(path12) {
|
|
309
|
+
var resolvedPath = path12.split(PATH_SEPARATOR)[0];
|
|
310
|
+
path12.split(PATH_SEPARATOR).forEach(function(name) {
|
|
311
|
+
if (!name || name.substr(-1, 1) === ":") return;
|
|
312
|
+
resolvedPath += PATH_SEPARATOR + name;
|
|
313
|
+
var stat;
|
|
314
|
+
try {
|
|
315
|
+
stat = fs10.statSync(resolvedPath);
|
|
316
|
+
} catch (e) {
|
|
317
|
+
fs10.mkdirSync(resolvedPath);
|
|
318
|
+
}
|
|
319
|
+
if (stat && stat.isFile())
|
|
320
|
+
throw Errors.FILE_IN_THE_WAY.replace("%s", resolvedPath);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
function findSync(dir, pattern, recoursive) {
|
|
324
|
+
if (typeof pattern === "boolean") {
|
|
325
|
+
recoursive = pattern;
|
|
326
|
+
pattern = void 0;
|
|
327
|
+
}
|
|
328
|
+
var files = [];
|
|
329
|
+
fs10.readdirSync(dir).forEach(function(file) {
|
|
330
|
+
var path12 = pth.join(dir, file);
|
|
331
|
+
if (fs10.statSync(path12).isDirectory() && recoursive)
|
|
332
|
+
files = files.concat(findSync(path12, pattern, recoursive));
|
|
333
|
+
if (!pattern || pattern.test(path12)) {
|
|
334
|
+
files.push(pth.normalize(path12) + (fs10.statSync(path12).isDirectory() ? PATH_SEPARATOR : ""));
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
return files;
|
|
338
|
+
}
|
|
339
|
+
function readBigUInt64LE(buffer, index) {
|
|
340
|
+
var slice = Buffer.from(buffer.slice(index, index + 8));
|
|
341
|
+
slice.swap64();
|
|
342
|
+
return parseInt(`0x${slice.toString("hex")}`);
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
makeDir: function(path12) {
|
|
346
|
+
mkdirSync(path12);
|
|
347
|
+
},
|
|
348
|
+
crc32: function(buf) {
|
|
349
|
+
if (typeof buf === "string") {
|
|
350
|
+
buf = Buffer.alloc(buf.length, buf);
|
|
351
|
+
}
|
|
352
|
+
var b = Buffer.alloc(4);
|
|
353
|
+
if (!crcTable.length) {
|
|
354
|
+
for (var n = 0; n < 256; n++) {
|
|
355
|
+
var c = n;
|
|
356
|
+
for (var k = 8; --k >= 0; )
|
|
357
|
+
if ((c & 1) !== 0) {
|
|
358
|
+
c = 3988292384 ^ c >>> 1;
|
|
359
|
+
} else {
|
|
360
|
+
c = c >>> 1;
|
|
361
|
+
}
|
|
362
|
+
if (c < 0) {
|
|
363
|
+
b.writeInt32LE(c, 0);
|
|
364
|
+
c = b.readUInt32LE(0);
|
|
365
|
+
}
|
|
366
|
+
crcTable[n] = c;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
var crc = 0, off = 0, len = buf.length, c1 = ~crc;
|
|
370
|
+
while (--len >= 0) c1 = crcTable[(c1 ^ buf[off++]) & 255] ^ c1 >>> 8;
|
|
371
|
+
crc = ~c1;
|
|
372
|
+
b.writeInt32LE(crc & 4294967295, 0);
|
|
373
|
+
return b.readUInt32LE(0);
|
|
374
|
+
},
|
|
375
|
+
methodToString: function(method) {
|
|
376
|
+
switch (method) {
|
|
377
|
+
case Constants.STORED:
|
|
378
|
+
return "STORED (" + method + ")";
|
|
379
|
+
case Constants.DEFLATED:
|
|
380
|
+
return "DEFLATED (" + method + ")";
|
|
381
|
+
default:
|
|
382
|
+
return "UNSUPPORTED (" + method + ")";
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
writeFileTo: function(path12, content, overwrite, attr) {
|
|
386
|
+
if (fs10.existsSync(path12)) {
|
|
387
|
+
if (!overwrite)
|
|
388
|
+
return false;
|
|
389
|
+
var stat = fs10.statSync(path12);
|
|
390
|
+
if (stat.isDirectory()) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
var folder = pth.dirname(path12);
|
|
395
|
+
if (!fs10.existsSync(folder)) {
|
|
396
|
+
mkdirSync(folder);
|
|
397
|
+
}
|
|
398
|
+
var fd;
|
|
399
|
+
try {
|
|
400
|
+
fd = fs10.openSync(path12, "w", 438);
|
|
401
|
+
} catch (e) {
|
|
402
|
+
fs10.chmodSync(path12, 438);
|
|
403
|
+
fd = fs10.openSync(path12, "w", 438);
|
|
404
|
+
}
|
|
405
|
+
if (fd) {
|
|
406
|
+
try {
|
|
407
|
+
fs10.writeSync(fd, content, 0, content.length, 0);
|
|
408
|
+
} catch (e) {
|
|
409
|
+
throw e;
|
|
410
|
+
} finally {
|
|
411
|
+
fs10.closeSync(fd);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
fs10.chmodSync(path12, attr || 438);
|
|
415
|
+
return true;
|
|
416
|
+
},
|
|
417
|
+
writeFileToAsync: function(path12, content, overwrite, attr, callback) {
|
|
418
|
+
if (typeof attr === "function") {
|
|
419
|
+
callback = attr;
|
|
420
|
+
attr = void 0;
|
|
421
|
+
}
|
|
422
|
+
fs10.exists(path12, function(exists) {
|
|
423
|
+
if (exists && !overwrite)
|
|
424
|
+
return callback(false);
|
|
425
|
+
fs10.stat(path12, function(err, stat) {
|
|
426
|
+
if (exists && stat.isDirectory()) {
|
|
427
|
+
return callback(false);
|
|
428
|
+
}
|
|
429
|
+
var folder = pth.dirname(path12);
|
|
430
|
+
fs10.exists(folder, function(exists2) {
|
|
431
|
+
if (!exists2)
|
|
432
|
+
mkdirSync(folder);
|
|
433
|
+
fs10.open(path12, "w", 438, function(err2, fd) {
|
|
434
|
+
if (err2) {
|
|
435
|
+
fs10.chmod(path12, 438, function() {
|
|
436
|
+
fs10.open(path12, "w", 438, function(err3, fd2) {
|
|
437
|
+
fs10.write(fd2, content, 0, content.length, 0, function() {
|
|
438
|
+
fs10.close(fd2, function() {
|
|
439
|
+
fs10.chmod(path12, attr || 438, function() {
|
|
440
|
+
callback(true);
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
if (fd) {
|
|
448
|
+
fs10.write(fd, content, 0, content.length, 0, function() {
|
|
449
|
+
fs10.close(fd, function() {
|
|
450
|
+
fs10.chmod(path12, attr || 438, function() {
|
|
451
|
+
callback(true);
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
} else {
|
|
456
|
+
fs10.chmod(path12, attr || 438, function() {
|
|
457
|
+
callback(true);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
},
|
|
466
|
+
findFiles: function(path12) {
|
|
467
|
+
return findSync(path12, true);
|
|
468
|
+
},
|
|
469
|
+
getAttributes: function(path12) {
|
|
470
|
+
},
|
|
471
|
+
setAttributes: function(path12) {
|
|
472
|
+
},
|
|
473
|
+
toBuffer: function(input) {
|
|
474
|
+
if (Buffer.isBuffer(input)) {
|
|
475
|
+
return input;
|
|
476
|
+
} else {
|
|
477
|
+
if (input.length === 0) {
|
|
478
|
+
return Buffer.alloc(0);
|
|
479
|
+
}
|
|
480
|
+
return Buffer.from(input, "utf8");
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
readBigUInt64LE,
|
|
484
|
+
Constants,
|
|
485
|
+
Errors
|
|
486
|
+
};
|
|
487
|
+
})();
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// ../../node_modules/adm-zip/util/fattr.js
|
|
492
|
+
var require_fattr = __commonJS({
|
|
493
|
+
"../../node_modules/adm-zip/util/fattr.js"(exports, module) {
|
|
494
|
+
var fs10 = require_fileSystem().require();
|
|
495
|
+
var pth = __require("path");
|
|
496
|
+
fs10.existsSync = fs10.existsSync || pth.existsSync;
|
|
497
|
+
module.exports = function(path12) {
|
|
498
|
+
var _path = path12 || "", _permissions = 0, _obj = newAttr(), _stat = null;
|
|
499
|
+
function newAttr() {
|
|
500
|
+
return {
|
|
501
|
+
directory: false,
|
|
502
|
+
readonly: false,
|
|
503
|
+
hidden: false,
|
|
504
|
+
executable: false,
|
|
505
|
+
mtime: 0,
|
|
506
|
+
atime: 0
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
if (_path && fs10.existsSync(_path)) {
|
|
510
|
+
_stat = fs10.statSync(_path);
|
|
511
|
+
_obj.directory = _stat.isDirectory();
|
|
512
|
+
_obj.mtime = _stat.mtime;
|
|
513
|
+
_obj.atime = _stat.atime;
|
|
514
|
+
_obj.executable = !!(1 & parseInt((_stat.mode & parseInt("777", 8)).toString(8)[0]));
|
|
515
|
+
_obj.readonly = !!(2 & parseInt((_stat.mode & parseInt("777", 8)).toString(8)[0]));
|
|
516
|
+
_obj.hidden = pth.basename(_path)[0] === ".";
|
|
517
|
+
} else {
|
|
518
|
+
console.warn("Invalid path: " + _path);
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
get directory() {
|
|
522
|
+
return _obj.directory;
|
|
523
|
+
},
|
|
524
|
+
get readOnly() {
|
|
525
|
+
return _obj.readonly;
|
|
526
|
+
},
|
|
527
|
+
get hidden() {
|
|
528
|
+
return _obj.hidden;
|
|
529
|
+
},
|
|
530
|
+
get mtime() {
|
|
531
|
+
return _obj.mtime;
|
|
532
|
+
},
|
|
533
|
+
get atime() {
|
|
534
|
+
return _obj.atime;
|
|
535
|
+
},
|
|
536
|
+
get executable() {
|
|
537
|
+
return _obj.executable;
|
|
538
|
+
},
|
|
539
|
+
decodeAttributes: function(val) {
|
|
540
|
+
},
|
|
541
|
+
encodeAttributes: function(val) {
|
|
542
|
+
},
|
|
543
|
+
toString: function() {
|
|
544
|
+
return '{\n "path" : "' + _path + ',\n "isDirectory" : ' + _obj.directory + ',\n "isReadOnly" : ' + _obj.readonly + ',\n "isHidden" : ' + _obj.hidden + ',\n "isExecutable" : ' + _obj.executable + ',\n "mTime" : ' + _obj.mtime + '\n "aTime" : ' + _obj.atime + "\n}";
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// ../../node_modules/adm-zip/util/index.js
|
|
552
|
+
var require_util = __commonJS({
|
|
553
|
+
"../../node_modules/adm-zip/util/index.js"(exports, module) {
|
|
554
|
+
module.exports = require_utils();
|
|
555
|
+
module.exports.FileSystem = require_fileSystem();
|
|
556
|
+
module.exports.Constants = require_constants();
|
|
557
|
+
module.exports.Errors = require_errors();
|
|
558
|
+
module.exports.FileAttr = require_fattr();
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
// ../../node_modules/adm-zip/headers/entryHeader.js
|
|
563
|
+
var require_entryHeader = __commonJS({
|
|
564
|
+
"../../node_modules/adm-zip/headers/entryHeader.js"(exports, module) {
|
|
565
|
+
var Utils = require_util();
|
|
566
|
+
var Constants = Utils.Constants;
|
|
567
|
+
module.exports = function() {
|
|
568
|
+
var _verMade = 10, _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;
|
|
569
|
+
var _dataHeader = {};
|
|
570
|
+
function setTime(val) {
|
|
571
|
+
val = new Date(val);
|
|
572
|
+
_time = (val.getFullYear() - 1980 & 127) << 25 | val.getMonth() + 1 << 21 | val.getDate() << 16 | val.getHours() << 11 | val.getMinutes() << 5 | val.getSeconds() >> 1;
|
|
573
|
+
}
|
|
574
|
+
setTime(+/* @__PURE__ */ new Date());
|
|
575
|
+
return {
|
|
576
|
+
get made() {
|
|
577
|
+
return _verMade;
|
|
578
|
+
},
|
|
579
|
+
set made(val) {
|
|
580
|
+
_verMade = val;
|
|
581
|
+
},
|
|
582
|
+
get version() {
|
|
583
|
+
return _version;
|
|
584
|
+
},
|
|
585
|
+
set version(val) {
|
|
586
|
+
_version = val;
|
|
587
|
+
},
|
|
588
|
+
get flags() {
|
|
589
|
+
return _flags;
|
|
590
|
+
},
|
|
591
|
+
set flags(val) {
|
|
592
|
+
_flags = val;
|
|
593
|
+
},
|
|
594
|
+
get method() {
|
|
595
|
+
return _method;
|
|
596
|
+
},
|
|
597
|
+
set method(val) {
|
|
598
|
+
_method = val;
|
|
599
|
+
},
|
|
600
|
+
get time() {
|
|
601
|
+
return new Date(
|
|
602
|
+
(_time >> 25 & 127) + 1980,
|
|
603
|
+
(_time >> 21 & 15) - 1,
|
|
604
|
+
_time >> 16 & 31,
|
|
605
|
+
_time >> 11 & 31,
|
|
606
|
+
_time >> 5 & 63,
|
|
607
|
+
(_time & 31) << 1
|
|
608
|
+
);
|
|
609
|
+
},
|
|
610
|
+
set time(val) {
|
|
611
|
+
setTime(val);
|
|
612
|
+
},
|
|
613
|
+
get crc() {
|
|
614
|
+
return _crc;
|
|
615
|
+
},
|
|
616
|
+
set crc(val) {
|
|
617
|
+
_crc = val;
|
|
618
|
+
},
|
|
619
|
+
get compressedSize() {
|
|
620
|
+
return _compressedSize;
|
|
621
|
+
},
|
|
622
|
+
set compressedSize(val) {
|
|
623
|
+
_compressedSize = val;
|
|
624
|
+
},
|
|
625
|
+
get size() {
|
|
626
|
+
return _size;
|
|
627
|
+
},
|
|
628
|
+
set size(val) {
|
|
629
|
+
_size = val;
|
|
630
|
+
},
|
|
631
|
+
get fileNameLength() {
|
|
632
|
+
return _fnameLen;
|
|
633
|
+
},
|
|
634
|
+
set fileNameLength(val) {
|
|
635
|
+
_fnameLen = val;
|
|
636
|
+
},
|
|
637
|
+
get extraLength() {
|
|
638
|
+
return _extraLen;
|
|
639
|
+
},
|
|
640
|
+
set extraLength(val) {
|
|
641
|
+
_extraLen = val;
|
|
642
|
+
},
|
|
643
|
+
get commentLength() {
|
|
644
|
+
return _comLen;
|
|
645
|
+
},
|
|
646
|
+
set commentLength(val) {
|
|
647
|
+
_comLen = val;
|
|
648
|
+
},
|
|
649
|
+
get diskNumStart() {
|
|
650
|
+
return _diskStart;
|
|
651
|
+
},
|
|
652
|
+
set diskNumStart(val) {
|
|
653
|
+
_diskStart = val;
|
|
654
|
+
},
|
|
655
|
+
get inAttr() {
|
|
656
|
+
return _inattr;
|
|
657
|
+
},
|
|
658
|
+
set inAttr(val) {
|
|
659
|
+
_inattr = val;
|
|
660
|
+
},
|
|
661
|
+
get attr() {
|
|
662
|
+
return _attr;
|
|
663
|
+
},
|
|
664
|
+
set attr(val) {
|
|
665
|
+
_attr = val;
|
|
666
|
+
},
|
|
667
|
+
get offset() {
|
|
668
|
+
return _offset;
|
|
669
|
+
},
|
|
670
|
+
set offset(val) {
|
|
671
|
+
_offset = val;
|
|
672
|
+
},
|
|
673
|
+
get encripted() {
|
|
674
|
+
return (_flags & 1) === 1;
|
|
675
|
+
},
|
|
676
|
+
get entryHeaderSize() {
|
|
677
|
+
return Constants.CENHDR + _fnameLen + _extraLen + _comLen;
|
|
678
|
+
},
|
|
679
|
+
get realDataOffset() {
|
|
680
|
+
return _offset + Constants.LOCHDR + _dataHeader.fnameLen + _dataHeader.extraLen;
|
|
681
|
+
},
|
|
682
|
+
get dataHeader() {
|
|
683
|
+
return _dataHeader;
|
|
684
|
+
},
|
|
685
|
+
loadDataHeaderFromBinary: function(input) {
|
|
686
|
+
var data = input.slice(_offset, _offset + Constants.LOCHDR);
|
|
687
|
+
if (data.readUInt32LE(0) !== Constants.LOCSIG) {
|
|
688
|
+
throw new Error(Utils.Errors.INVALID_LOC);
|
|
689
|
+
}
|
|
690
|
+
_dataHeader = {
|
|
691
|
+
// version needed to extract
|
|
692
|
+
version: data.readUInt16LE(Constants.LOCVER),
|
|
693
|
+
// general purpose bit flag
|
|
694
|
+
flags: data.readUInt16LE(Constants.LOCFLG),
|
|
695
|
+
// compression method
|
|
696
|
+
method: data.readUInt16LE(Constants.LOCHOW),
|
|
697
|
+
// modification time (2 bytes time, 2 bytes date)
|
|
698
|
+
time: data.readUInt32LE(Constants.LOCTIM),
|
|
699
|
+
// uncompressed file crc-32 value
|
|
700
|
+
crc: data.readUInt32LE(Constants.LOCCRC),
|
|
701
|
+
// compressed size
|
|
702
|
+
compressedSize: data.readUInt32LE(Constants.LOCSIZ),
|
|
703
|
+
// uncompressed size
|
|
704
|
+
size: data.readUInt32LE(Constants.LOCLEN),
|
|
705
|
+
// filename length
|
|
706
|
+
fnameLen: data.readUInt16LE(Constants.LOCNAM),
|
|
707
|
+
// extra field length
|
|
708
|
+
extraLen: data.readUInt16LE(Constants.LOCEXT)
|
|
709
|
+
};
|
|
710
|
+
},
|
|
711
|
+
loadFromBinary: function(data) {
|
|
712
|
+
if (data.length !== Constants.CENHDR || data.readUInt32LE(0) !== Constants.CENSIG) {
|
|
713
|
+
throw new Error(Utils.Errors.INVALID_CEN);
|
|
714
|
+
}
|
|
715
|
+
_verMade = data.readUInt16LE(Constants.CENVEM);
|
|
716
|
+
_version = data.readUInt16LE(Constants.CENVER);
|
|
717
|
+
_flags = data.readUInt16LE(Constants.CENFLG);
|
|
718
|
+
_method = data.readUInt16LE(Constants.CENHOW);
|
|
719
|
+
_time = data.readUInt32LE(Constants.CENTIM);
|
|
720
|
+
_crc = data.readUInt32LE(Constants.CENCRC);
|
|
721
|
+
_compressedSize = data.readUInt32LE(Constants.CENSIZ);
|
|
722
|
+
_size = data.readUInt32LE(Constants.CENLEN);
|
|
723
|
+
_fnameLen = data.readUInt16LE(Constants.CENNAM);
|
|
724
|
+
_extraLen = data.readUInt16LE(Constants.CENEXT);
|
|
725
|
+
_comLen = data.readUInt16LE(Constants.CENCOM);
|
|
726
|
+
_diskStart = data.readUInt16LE(Constants.CENDSK);
|
|
727
|
+
_inattr = data.readUInt16LE(Constants.CENATT);
|
|
728
|
+
_attr = data.readUInt32LE(Constants.CENATX);
|
|
729
|
+
_offset = data.readUInt32LE(Constants.CENOFF);
|
|
730
|
+
},
|
|
731
|
+
dataHeaderToBinary: function() {
|
|
732
|
+
var data = Buffer.alloc(Constants.LOCHDR);
|
|
733
|
+
data.writeUInt32LE(Constants.LOCSIG, 0);
|
|
734
|
+
data.writeUInt16LE(_version, Constants.LOCVER);
|
|
735
|
+
data.writeUInt16LE(_flags, Constants.LOCFLG);
|
|
736
|
+
data.writeUInt16LE(_method, Constants.LOCHOW);
|
|
737
|
+
data.writeUInt32LE(_time, Constants.LOCTIM);
|
|
738
|
+
data.writeUInt32LE(_crc, Constants.LOCCRC);
|
|
739
|
+
data.writeUInt32LE(_compressedSize, Constants.LOCSIZ);
|
|
740
|
+
data.writeUInt32LE(_size, Constants.LOCLEN);
|
|
741
|
+
data.writeUInt16LE(_fnameLen, Constants.LOCNAM);
|
|
742
|
+
data.writeUInt16LE(_extraLen, Constants.LOCEXT);
|
|
743
|
+
return data;
|
|
744
|
+
},
|
|
745
|
+
entryHeaderToBinary: function() {
|
|
746
|
+
var data = Buffer.alloc(Constants.CENHDR + _fnameLen + _extraLen + _comLen);
|
|
747
|
+
data.writeUInt32LE(Constants.CENSIG, 0);
|
|
748
|
+
data.writeUInt16LE(_verMade, Constants.CENVEM);
|
|
749
|
+
data.writeUInt16LE(_version, Constants.CENVER);
|
|
750
|
+
data.writeUInt16LE(_flags, Constants.CENFLG);
|
|
751
|
+
data.writeUInt16LE(_method, Constants.CENHOW);
|
|
752
|
+
data.writeUInt32LE(_time, Constants.CENTIM);
|
|
753
|
+
data.writeUInt32LE(_crc, Constants.CENCRC);
|
|
754
|
+
data.writeUInt32LE(_compressedSize, Constants.CENSIZ);
|
|
755
|
+
data.writeUInt32LE(_size, Constants.CENLEN);
|
|
756
|
+
data.writeUInt16LE(_fnameLen, Constants.CENNAM);
|
|
757
|
+
data.writeUInt16LE(_extraLen, Constants.CENEXT);
|
|
758
|
+
data.writeUInt16LE(_comLen, Constants.CENCOM);
|
|
759
|
+
data.writeUInt16LE(_diskStart, Constants.CENDSK);
|
|
760
|
+
data.writeUInt16LE(_inattr, Constants.CENATT);
|
|
761
|
+
data.writeUInt32LE(_attr, Constants.CENATX);
|
|
762
|
+
data.writeUInt32LE(_offset, Constants.CENOFF);
|
|
763
|
+
data.fill(0, Constants.CENHDR);
|
|
764
|
+
return data;
|
|
765
|
+
},
|
|
766
|
+
toString: function() {
|
|
767
|
+
return '{\n "made" : ' + _verMade + ',\n "version" : ' + _version + ',\n "flags" : ' + _flags + ',\n "method" : ' + Utils.methodToString(_method) + ',\n "time" : ' + this.time + ',\n "crc" : 0x' + _crc.toString(16).toUpperCase() + ',\n "compressedSize" : ' + _compressedSize + ' bytes,\n "size" : ' + _size + ' bytes,\n "fileNameLength" : ' + _fnameLen + ',\n "extraLength" : ' + _extraLen + ' bytes,\n "commentLength" : ' + _comLen + ' bytes,\n "diskNumStart" : ' + _diskStart + ',\n "inAttr" : ' + _inattr + ',\n "attr" : ' + _attr + ',\n "offset" : ' + _offset + ',\n "entryHeaderSize" : ' + (Constants.CENHDR + _fnameLen + _extraLen + _comLen) + " bytes\n}";
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// ../../node_modules/adm-zip/headers/mainHeader.js
|
|
775
|
+
var require_mainHeader = __commonJS({
|
|
776
|
+
"../../node_modules/adm-zip/headers/mainHeader.js"(exports, module) {
|
|
777
|
+
var Utils = require_util();
|
|
778
|
+
var Constants = Utils.Constants;
|
|
779
|
+
module.exports = function() {
|
|
780
|
+
var _volumeEntries = 0, _totalEntries = 0, _size = 0, _offset = 0, _commentLength = 0;
|
|
781
|
+
return {
|
|
782
|
+
get diskEntries() {
|
|
783
|
+
return _volumeEntries;
|
|
784
|
+
},
|
|
785
|
+
set diskEntries(val) {
|
|
786
|
+
_volumeEntries = _totalEntries = val;
|
|
787
|
+
},
|
|
788
|
+
get totalEntries() {
|
|
789
|
+
return _totalEntries;
|
|
790
|
+
},
|
|
791
|
+
set totalEntries(val) {
|
|
792
|
+
_totalEntries = _volumeEntries = val;
|
|
793
|
+
},
|
|
794
|
+
get size() {
|
|
795
|
+
return _size;
|
|
796
|
+
},
|
|
797
|
+
set size(val) {
|
|
798
|
+
_size = val;
|
|
799
|
+
},
|
|
800
|
+
get offset() {
|
|
801
|
+
return _offset;
|
|
802
|
+
},
|
|
803
|
+
set offset(val) {
|
|
804
|
+
_offset = val;
|
|
805
|
+
},
|
|
806
|
+
get commentLength() {
|
|
807
|
+
return _commentLength;
|
|
808
|
+
},
|
|
809
|
+
set commentLength(val) {
|
|
810
|
+
_commentLength = val;
|
|
811
|
+
},
|
|
812
|
+
get mainHeaderSize() {
|
|
813
|
+
return Constants.ENDHDR + _commentLength;
|
|
814
|
+
},
|
|
815
|
+
loadFromBinary: function(data) {
|
|
816
|
+
if ((data.length !== Constants.ENDHDR || data.readUInt32LE(0) !== Constants.ENDSIG) && (data.length < Constants.ZIP64HDR || data.readUInt32LE(0) !== Constants.ZIP64SIG)) {
|
|
817
|
+
throw new Error(Utils.Errors.INVALID_END);
|
|
818
|
+
}
|
|
819
|
+
if (data.readUInt32LE(0) === Constants.ENDSIG) {
|
|
820
|
+
_volumeEntries = data.readUInt16LE(Constants.ENDSUB);
|
|
821
|
+
_totalEntries = data.readUInt16LE(Constants.ENDTOT);
|
|
822
|
+
_size = data.readUInt32LE(Constants.ENDSIZ);
|
|
823
|
+
_offset = data.readUInt32LE(Constants.ENDOFF);
|
|
824
|
+
_commentLength = data.readUInt16LE(Constants.ENDCOM);
|
|
825
|
+
} else {
|
|
826
|
+
_volumeEntries = Utils.readBigUInt64LE(data, Constants.ZIP64SUB);
|
|
827
|
+
_totalEntries = Utils.readBigUInt64LE(data, Constants.ZIP64TOT);
|
|
828
|
+
_size = Utils.readBigUInt64LE(data, Constants.ZIP64SIZ);
|
|
829
|
+
_offset = Utils.readBigUInt64LE(data, Constants.ZIP64OFF);
|
|
830
|
+
_commentLength = 0;
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
toBinary: function() {
|
|
834
|
+
var b = Buffer.alloc(Constants.ENDHDR + _commentLength);
|
|
835
|
+
b.writeUInt32LE(Constants.ENDSIG, 0);
|
|
836
|
+
b.writeUInt32LE(0, 4);
|
|
837
|
+
b.writeUInt16LE(_volumeEntries, Constants.ENDSUB);
|
|
838
|
+
b.writeUInt16LE(_totalEntries, Constants.ENDTOT);
|
|
839
|
+
b.writeUInt32LE(_size, Constants.ENDSIZ);
|
|
840
|
+
b.writeUInt32LE(_offset, Constants.ENDOFF);
|
|
841
|
+
b.writeUInt16LE(_commentLength, Constants.ENDCOM);
|
|
842
|
+
b.fill(" ", Constants.ENDHDR);
|
|
843
|
+
return b;
|
|
844
|
+
},
|
|
845
|
+
toString: function() {
|
|
846
|
+
return '{\n "diskEntries" : ' + _volumeEntries + ',\n "totalEntries" : ' + _totalEntries + ',\n "size" : ' + _size + ' bytes,\n "offset" : 0x' + _offset.toString(16).toUpperCase() + ',\n "commentLength" : 0x' + _commentLength + "\n}";
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
// ../../node_modules/adm-zip/headers/index.js
|
|
854
|
+
var require_headers = __commonJS({
|
|
855
|
+
"../../node_modules/adm-zip/headers/index.js"(exports) {
|
|
856
|
+
exports.EntryHeader = require_entryHeader();
|
|
857
|
+
exports.MainHeader = require_mainHeader();
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// ../../node_modules/adm-zip/methods/deflater.js
|
|
862
|
+
var require_deflater = __commonJS({
|
|
863
|
+
"../../node_modules/adm-zip/methods/deflater.js"(exports, module) {
|
|
864
|
+
module.exports = function(inbuf) {
|
|
865
|
+
var zlib = __require("zlib");
|
|
866
|
+
var opts = { chunkSize: (parseInt(inbuf.length / 1024) + 1) * 1024 };
|
|
867
|
+
return {
|
|
868
|
+
deflate: function() {
|
|
869
|
+
return zlib.deflateRawSync(inbuf, opts);
|
|
870
|
+
},
|
|
871
|
+
deflateAsync: function(callback) {
|
|
872
|
+
var tmp = zlib.createDeflateRaw(opts), parts = [], total = 0;
|
|
873
|
+
tmp.on("data", function(data) {
|
|
874
|
+
parts.push(data);
|
|
875
|
+
total += data.length;
|
|
876
|
+
});
|
|
877
|
+
tmp.on("end", function() {
|
|
878
|
+
var buf = Buffer.alloc(total), written = 0;
|
|
879
|
+
buf.fill(0);
|
|
880
|
+
for (var i = 0; i < parts.length; i++) {
|
|
881
|
+
var part = parts[i];
|
|
882
|
+
part.copy(buf, written);
|
|
883
|
+
written += part.length;
|
|
884
|
+
}
|
|
885
|
+
callback && callback(buf);
|
|
886
|
+
});
|
|
887
|
+
tmp.end(inbuf);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
// ../../node_modules/adm-zip/methods/inflater.js
|
|
895
|
+
var require_inflater = __commonJS({
|
|
896
|
+
"../../node_modules/adm-zip/methods/inflater.js"(exports, module) {
|
|
897
|
+
module.exports = function(inbuf) {
|
|
898
|
+
var zlib = __require("zlib");
|
|
899
|
+
return {
|
|
900
|
+
inflate: function() {
|
|
901
|
+
return zlib.inflateRawSync(inbuf);
|
|
902
|
+
},
|
|
903
|
+
inflateAsync: function(callback) {
|
|
904
|
+
var tmp = zlib.createInflateRaw(), parts = [], total = 0;
|
|
905
|
+
tmp.on("data", function(data) {
|
|
906
|
+
parts.push(data);
|
|
907
|
+
total += data.length;
|
|
908
|
+
});
|
|
909
|
+
tmp.on("end", function() {
|
|
910
|
+
var buf = Buffer.alloc(total), written = 0;
|
|
911
|
+
buf.fill(0);
|
|
912
|
+
for (var i = 0; i < parts.length; i++) {
|
|
913
|
+
var part = parts[i];
|
|
914
|
+
part.copy(buf, written);
|
|
915
|
+
written += part.length;
|
|
916
|
+
}
|
|
917
|
+
callback && callback(buf);
|
|
918
|
+
});
|
|
919
|
+
tmp.end(inbuf);
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
// ../../node_modules/adm-zip/methods/index.js
|
|
927
|
+
var require_methods = __commonJS({
|
|
928
|
+
"../../node_modules/adm-zip/methods/index.js"(exports) {
|
|
929
|
+
exports.Deflater = require_deflater();
|
|
930
|
+
exports.Inflater = require_inflater();
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
// ../../node_modules/adm-zip/zipEntry.js
|
|
935
|
+
var require_zipEntry = __commonJS({
|
|
936
|
+
"../../node_modules/adm-zip/zipEntry.js"(exports, module) {
|
|
937
|
+
var Utils = require_util();
|
|
938
|
+
var Headers = require_headers();
|
|
939
|
+
var Constants = Utils.Constants;
|
|
940
|
+
var Methods = require_methods();
|
|
941
|
+
module.exports = function(input) {
|
|
942
|
+
var _entryHeader = new Headers.EntryHeader(), _entryName = Buffer.alloc(0), _comment = Buffer.alloc(0), _isDirectory = false, uncompressedData = null, _extra = Buffer.alloc(0);
|
|
943
|
+
function getCompressedDataFromZip() {
|
|
944
|
+
if (!input || !Buffer.isBuffer(input)) {
|
|
945
|
+
return Buffer.alloc(0);
|
|
946
|
+
}
|
|
947
|
+
_entryHeader.loadDataHeaderFromBinary(input);
|
|
948
|
+
return input.slice(_entryHeader.realDataOffset, _entryHeader.realDataOffset + _entryHeader.compressedSize);
|
|
949
|
+
}
|
|
950
|
+
function crc32OK(data) {
|
|
951
|
+
if ((_entryHeader.flags & 8) !== 8) {
|
|
952
|
+
if (Utils.crc32(data) !== _entryHeader.dataHeader.crc) {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
} else {
|
|
956
|
+
}
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
function decompress(async, callback, pass) {
|
|
960
|
+
if (typeof callback === "undefined" && typeof async === "string") {
|
|
961
|
+
pass = async;
|
|
962
|
+
async = void 0;
|
|
963
|
+
}
|
|
964
|
+
if (_isDirectory) {
|
|
965
|
+
if (async && callback) {
|
|
966
|
+
callback(Buffer.alloc(0), Utils.Errors.DIRECTORY_CONTENT_ERROR);
|
|
967
|
+
}
|
|
968
|
+
return Buffer.alloc(0);
|
|
969
|
+
}
|
|
970
|
+
var compressedData = getCompressedDataFromZip();
|
|
971
|
+
if (compressedData.length === 0) {
|
|
972
|
+
if (async && callback) callback(compressedData);
|
|
973
|
+
return compressedData;
|
|
974
|
+
}
|
|
975
|
+
var data = Buffer.alloc(_entryHeader.size);
|
|
976
|
+
switch (_entryHeader.method) {
|
|
977
|
+
case Utils.Constants.STORED:
|
|
978
|
+
compressedData.copy(data);
|
|
979
|
+
if (!crc32OK(data)) {
|
|
980
|
+
if (async && callback) callback(data, Utils.Errors.BAD_CRC);
|
|
981
|
+
throw new Error(Utils.Errors.BAD_CRC);
|
|
982
|
+
} else {
|
|
983
|
+
if (async && callback) callback(data);
|
|
984
|
+
return data;
|
|
985
|
+
}
|
|
986
|
+
case Utils.Constants.DEFLATED:
|
|
987
|
+
var inflater = new Methods.Inflater(compressedData);
|
|
988
|
+
if (!async) {
|
|
989
|
+
var result = inflater.inflate(data);
|
|
990
|
+
result.copy(data, 0);
|
|
991
|
+
if (!crc32OK(data)) {
|
|
992
|
+
throw new Error(Utils.Errors.BAD_CRC + " " + _entryName.toString());
|
|
993
|
+
}
|
|
994
|
+
return data;
|
|
995
|
+
} else {
|
|
996
|
+
inflater.inflateAsync(function(result2) {
|
|
997
|
+
result2.copy(data, 0);
|
|
998
|
+
if (!crc32OK(data)) {
|
|
999
|
+
if (callback) callback(data, Utils.Errors.BAD_CRC);
|
|
1000
|
+
} else {
|
|
1001
|
+
if (callback) callback(data);
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
break;
|
|
1006
|
+
default:
|
|
1007
|
+
if (async && callback) callback(Buffer.alloc(0), Utils.Errors.UNKNOWN_METHOD);
|
|
1008
|
+
throw new Error(Utils.Errors.UNKNOWN_METHOD);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
function compress(async, callback) {
|
|
1012
|
+
if ((!uncompressedData || !uncompressedData.length) && Buffer.isBuffer(input)) {
|
|
1013
|
+
if (async && callback) callback(getCompressedDataFromZip());
|
|
1014
|
+
return getCompressedDataFromZip();
|
|
1015
|
+
}
|
|
1016
|
+
if (uncompressedData.length && !_isDirectory) {
|
|
1017
|
+
var compressedData;
|
|
1018
|
+
switch (_entryHeader.method) {
|
|
1019
|
+
case Utils.Constants.STORED:
|
|
1020
|
+
_entryHeader.compressedSize = _entryHeader.size;
|
|
1021
|
+
compressedData = Buffer.alloc(uncompressedData.length);
|
|
1022
|
+
uncompressedData.copy(compressedData);
|
|
1023
|
+
if (async && callback) callback(compressedData);
|
|
1024
|
+
return compressedData;
|
|
1025
|
+
default:
|
|
1026
|
+
case Utils.Constants.DEFLATED:
|
|
1027
|
+
var deflater = new Methods.Deflater(uncompressedData);
|
|
1028
|
+
if (!async) {
|
|
1029
|
+
var deflated = deflater.deflate();
|
|
1030
|
+
_entryHeader.compressedSize = deflated.length;
|
|
1031
|
+
return deflated;
|
|
1032
|
+
} else {
|
|
1033
|
+
deflater.deflateAsync(function(data) {
|
|
1034
|
+
compressedData = Buffer.alloc(data.length);
|
|
1035
|
+
_entryHeader.compressedSize = data.length;
|
|
1036
|
+
data.copy(compressedData);
|
|
1037
|
+
callback && callback(compressedData);
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
deflater = null;
|
|
1041
|
+
break;
|
|
1042
|
+
}
|
|
1043
|
+
} else {
|
|
1044
|
+
if (async && callback) {
|
|
1045
|
+
callback(Buffer.alloc(0));
|
|
1046
|
+
} else {
|
|
1047
|
+
return Buffer.alloc(0);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
function readUInt64LE(buffer, offset) {
|
|
1052
|
+
return (buffer.readUInt32LE(offset + 4) << 4) + buffer.readUInt32LE(offset);
|
|
1053
|
+
}
|
|
1054
|
+
function parseExtra(data) {
|
|
1055
|
+
var offset = 0;
|
|
1056
|
+
var signature, size, part;
|
|
1057
|
+
while (offset < data.length) {
|
|
1058
|
+
signature = data.readUInt16LE(offset);
|
|
1059
|
+
offset += 2;
|
|
1060
|
+
size = data.readUInt16LE(offset);
|
|
1061
|
+
offset += 2;
|
|
1062
|
+
part = data.slice(offset, offset + size);
|
|
1063
|
+
offset += size;
|
|
1064
|
+
if (Constants.ID_ZIP64 === signature) {
|
|
1065
|
+
parseZip64ExtendedInformation(part);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
function parseZip64ExtendedInformation(data) {
|
|
1070
|
+
var size, compressedSize, offset, diskNumStart;
|
|
1071
|
+
if (data.length >= Constants.EF_ZIP64_SCOMP) {
|
|
1072
|
+
size = readUInt64LE(data, Constants.EF_ZIP64_SUNCOMP);
|
|
1073
|
+
if (_entryHeader.size === Constants.EF_ZIP64_OR_32) {
|
|
1074
|
+
_entryHeader.size = size;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
if (data.length >= Constants.EF_ZIP64_RHO) {
|
|
1078
|
+
compressedSize = readUInt64LE(data, Constants.EF_ZIP64_SCOMP);
|
|
1079
|
+
if (_entryHeader.compressedSize === Constants.EF_ZIP64_OR_32) {
|
|
1080
|
+
_entryHeader.compressedSize = compressedSize;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
if (data.length >= Constants.EF_ZIP64_DSN) {
|
|
1084
|
+
offset = readUInt64LE(data, Constants.EF_ZIP64_RHO);
|
|
1085
|
+
if (_entryHeader.offset === Constants.EF_ZIP64_OR_32) {
|
|
1086
|
+
_entryHeader.offset = offset;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
if (data.length >= Constants.EF_ZIP64_DSN + 4) {
|
|
1090
|
+
diskNumStart = data.readUInt32LE(Constants.EF_ZIP64_DSN);
|
|
1091
|
+
if (_entryHeader.diskNumStart === Constants.EF_ZIP64_OR_16) {
|
|
1092
|
+
_entryHeader.diskNumStart = diskNumStart;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
return {
|
|
1097
|
+
get entryName() {
|
|
1098
|
+
return _entryName.toString();
|
|
1099
|
+
},
|
|
1100
|
+
get rawEntryName() {
|
|
1101
|
+
return _entryName;
|
|
1102
|
+
},
|
|
1103
|
+
set entryName(val) {
|
|
1104
|
+
_entryName = Utils.toBuffer(val);
|
|
1105
|
+
var lastChar = _entryName[_entryName.length - 1];
|
|
1106
|
+
_isDirectory = lastChar === 47 || lastChar === 92;
|
|
1107
|
+
_entryHeader.fileNameLength = _entryName.length;
|
|
1108
|
+
},
|
|
1109
|
+
get extra() {
|
|
1110
|
+
return _extra;
|
|
1111
|
+
},
|
|
1112
|
+
set extra(val) {
|
|
1113
|
+
_extra = val;
|
|
1114
|
+
_entryHeader.extraLength = val.length;
|
|
1115
|
+
parseExtra(val);
|
|
1116
|
+
},
|
|
1117
|
+
get comment() {
|
|
1118
|
+
return _comment.toString();
|
|
1119
|
+
},
|
|
1120
|
+
set comment(val) {
|
|
1121
|
+
_comment = Utils.toBuffer(val);
|
|
1122
|
+
_entryHeader.commentLength = _comment.length;
|
|
1123
|
+
},
|
|
1124
|
+
get name() {
|
|
1125
|
+
var n = _entryName.toString();
|
|
1126
|
+
return _isDirectory ? n.substr(n.length - 1).split("/").pop() : n.split("/").pop();
|
|
1127
|
+
},
|
|
1128
|
+
get isDirectory() {
|
|
1129
|
+
return _isDirectory;
|
|
1130
|
+
},
|
|
1131
|
+
getCompressedData: function() {
|
|
1132
|
+
return compress(false, null);
|
|
1133
|
+
},
|
|
1134
|
+
getCompressedDataAsync: function(callback) {
|
|
1135
|
+
compress(true, callback);
|
|
1136
|
+
},
|
|
1137
|
+
setData: function(value) {
|
|
1138
|
+
uncompressedData = Utils.toBuffer(value);
|
|
1139
|
+
if (!_isDirectory && uncompressedData.length) {
|
|
1140
|
+
_entryHeader.size = uncompressedData.length;
|
|
1141
|
+
_entryHeader.method = Utils.Constants.DEFLATED;
|
|
1142
|
+
_entryHeader.crc = Utils.crc32(value);
|
|
1143
|
+
_entryHeader.changed = true;
|
|
1144
|
+
} else {
|
|
1145
|
+
_entryHeader.method = Utils.Constants.STORED;
|
|
1146
|
+
}
|
|
1147
|
+
},
|
|
1148
|
+
getData: function(pass) {
|
|
1149
|
+
if (_entryHeader.changed) {
|
|
1150
|
+
return uncompressedData;
|
|
1151
|
+
} else {
|
|
1152
|
+
return decompress(false, null, pass);
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
1155
|
+
getDataAsync: function(callback, pass) {
|
|
1156
|
+
if (_entryHeader.changed) {
|
|
1157
|
+
callback(uncompressedData);
|
|
1158
|
+
} else {
|
|
1159
|
+
decompress(true, callback, pass);
|
|
1160
|
+
}
|
|
1161
|
+
},
|
|
1162
|
+
set attr(attr) {
|
|
1163
|
+
_entryHeader.attr = attr;
|
|
1164
|
+
},
|
|
1165
|
+
get attr() {
|
|
1166
|
+
return _entryHeader.attr;
|
|
1167
|
+
},
|
|
1168
|
+
set header(data) {
|
|
1169
|
+
_entryHeader.loadFromBinary(data);
|
|
1170
|
+
},
|
|
1171
|
+
get header() {
|
|
1172
|
+
return _entryHeader;
|
|
1173
|
+
},
|
|
1174
|
+
packHeader: function() {
|
|
1175
|
+
var header = _entryHeader.entryHeaderToBinary();
|
|
1176
|
+
_entryName.copy(header, Utils.Constants.CENHDR);
|
|
1177
|
+
if (_entryHeader.extraLength) {
|
|
1178
|
+
_extra.copy(header, Utils.Constants.CENHDR + _entryName.length);
|
|
1179
|
+
}
|
|
1180
|
+
if (_entryHeader.commentLength) {
|
|
1181
|
+
_comment.copy(header, Utils.Constants.CENHDR + _entryName.length + _entryHeader.extraLength, _comment.length);
|
|
1182
|
+
}
|
|
1183
|
+
return header;
|
|
1184
|
+
},
|
|
1185
|
+
toString: function() {
|
|
1186
|
+
return '{\n "entryName" : "' + _entryName.toString() + '",\n "name" : "' + (_isDirectory ? _entryName.toString().replace(/\/$/, "").split("/").pop() : _entryName.toString().split("/").pop()) + '",\n "comment" : "' + _comment.toString() + '",\n "isDirectory" : ' + _isDirectory + ',\n "header" : ' + _entryHeader.toString().replace(/\t/mg, " ").replace(/}/mg, " }") + ',\n "compressedData" : <' + (input && input.length + " bytes buffer" || "null") + '>\n "data" : <' + (uncompressedData && uncompressedData.length + " bytes buffer" || "null") + ">\n}";
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
|
|
1193
|
+
// ../../node_modules/adm-zip/zipFile.js
|
|
1194
|
+
var require_zipFile = __commonJS({
|
|
1195
|
+
"../../node_modules/adm-zip/zipFile.js"(exports, module) {
|
|
1196
|
+
var ZipEntry = require_zipEntry();
|
|
1197
|
+
var Headers = require_headers();
|
|
1198
|
+
var Utils = require_util();
|
|
1199
|
+
module.exports = function(input, inputType) {
|
|
1200
|
+
var entryList = [], entryTable = {}, _comment = Buffer.alloc(0), filename = "", fs10 = Utils.FileSystem.require(), inBuffer = null, mainHeader = new Headers.MainHeader(), loadedEntries = false;
|
|
1201
|
+
if (inputType === Utils.Constants.FILE) {
|
|
1202
|
+
filename = input;
|
|
1203
|
+
inBuffer = fs10.readFileSync(filename);
|
|
1204
|
+
readMainHeader();
|
|
1205
|
+
} else if (inputType === Utils.Constants.BUFFER) {
|
|
1206
|
+
inBuffer = input;
|
|
1207
|
+
readMainHeader();
|
|
1208
|
+
} else {
|
|
1209
|
+
loadedEntries = true;
|
|
1210
|
+
}
|
|
1211
|
+
function iterateEntries(callback) {
|
|
1212
|
+
const totalEntries = mainHeader.diskEntries;
|
|
1213
|
+
let index = mainHeader.offset;
|
|
1214
|
+
for (let i = 0; i < totalEntries; i++) {
|
|
1215
|
+
let tmp = index;
|
|
1216
|
+
const entry = new ZipEntry(inBuffer);
|
|
1217
|
+
entry.header = inBuffer.slice(tmp, tmp += Utils.Constants.CENHDR);
|
|
1218
|
+
entry.entryName = inBuffer.slice(tmp, tmp += entry.header.fileNameLength);
|
|
1219
|
+
index += entry.header.entryHeaderSize;
|
|
1220
|
+
callback(entry);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
function readEntries() {
|
|
1224
|
+
loadedEntries = true;
|
|
1225
|
+
entryTable = {};
|
|
1226
|
+
entryList = new Array(mainHeader.diskEntries);
|
|
1227
|
+
var index = mainHeader.offset;
|
|
1228
|
+
for (var i = 0; i < entryList.length; i++) {
|
|
1229
|
+
var tmp = index, entry = new ZipEntry(inBuffer);
|
|
1230
|
+
entry.header = inBuffer.slice(tmp, tmp += Utils.Constants.CENHDR);
|
|
1231
|
+
entry.entryName = inBuffer.slice(tmp, tmp += entry.header.fileNameLength);
|
|
1232
|
+
if (entry.header.extraLength) {
|
|
1233
|
+
entry.extra = inBuffer.slice(tmp, tmp += entry.header.extraLength);
|
|
1234
|
+
}
|
|
1235
|
+
if (entry.header.commentLength)
|
|
1236
|
+
entry.comment = inBuffer.slice(tmp, tmp + entry.header.commentLength);
|
|
1237
|
+
index += entry.header.entryHeaderSize;
|
|
1238
|
+
entryList[i] = entry;
|
|
1239
|
+
entryTable[entry.entryName] = entry;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function readMainHeader() {
|
|
1243
|
+
var i = inBuffer.length - Utils.Constants.ENDHDR, max = Math.max(0, i - 65535), n = max, endStart = inBuffer.length, endOffset = -1, commentEnd = 0;
|
|
1244
|
+
for (i; i >= n; i--) {
|
|
1245
|
+
if (inBuffer[i] !== 80) continue;
|
|
1246
|
+
if (inBuffer.readUInt32LE(i) === Utils.Constants.ENDSIG) {
|
|
1247
|
+
endOffset = i;
|
|
1248
|
+
commentEnd = i;
|
|
1249
|
+
endStart = i + Utils.Constants.ENDHDR;
|
|
1250
|
+
n = i - Utils.Constants.END64HDR;
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
if (inBuffer.readUInt32LE(i) === Utils.Constants.END64SIG) {
|
|
1254
|
+
n = max;
|
|
1255
|
+
continue;
|
|
1256
|
+
}
|
|
1257
|
+
if (inBuffer.readUInt32LE(i) == Utils.Constants.ZIP64SIG) {
|
|
1258
|
+
endOffset = i;
|
|
1259
|
+
endStart = i + Utils.readBigUInt64LE(inBuffer, i + Utils.Constants.ZIP64SIZE) + Utils.Constants.ZIP64LEAD;
|
|
1260
|
+
break;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
if (!~endOffset)
|
|
1264
|
+
throw new Error(Utils.Errors.INVALID_FORMAT);
|
|
1265
|
+
mainHeader.loadFromBinary(inBuffer.slice(endOffset, endStart));
|
|
1266
|
+
if (mainHeader.commentLength) {
|
|
1267
|
+
_comment = inBuffer.slice(commentEnd + Utils.Constants.ENDHDR);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return {
|
|
1271
|
+
/**
|
|
1272
|
+
* Returns an array of ZipEntry objects existent in the current opened archive
|
|
1273
|
+
* @return Array
|
|
1274
|
+
*/
|
|
1275
|
+
get entries() {
|
|
1276
|
+
if (!loadedEntries) {
|
|
1277
|
+
readEntries();
|
|
1278
|
+
}
|
|
1279
|
+
return entryList;
|
|
1280
|
+
},
|
|
1281
|
+
/**
|
|
1282
|
+
* Archive comment
|
|
1283
|
+
* @return {String}
|
|
1284
|
+
*/
|
|
1285
|
+
get comment() {
|
|
1286
|
+
return _comment.toString();
|
|
1287
|
+
},
|
|
1288
|
+
set comment(val) {
|
|
1289
|
+
mainHeader.commentLength = val.length;
|
|
1290
|
+
_comment = val;
|
|
1291
|
+
},
|
|
1292
|
+
getEntryCount: function() {
|
|
1293
|
+
if (!loadedEntries) {
|
|
1294
|
+
return mainHeader.diskEntries;
|
|
1295
|
+
}
|
|
1296
|
+
return entryList.length;
|
|
1297
|
+
},
|
|
1298
|
+
forEach: function(callback) {
|
|
1299
|
+
if (!loadedEntries) {
|
|
1300
|
+
iterateEntries(callback);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
entryList.forEach(callback);
|
|
1304
|
+
},
|
|
1305
|
+
/**
|
|
1306
|
+
* Returns a reference to the entry with the given name or null if entry is inexistent
|
|
1307
|
+
*
|
|
1308
|
+
* @param entryName
|
|
1309
|
+
* @return ZipEntry
|
|
1310
|
+
*/
|
|
1311
|
+
getEntry: function(entryName) {
|
|
1312
|
+
if (!loadedEntries) {
|
|
1313
|
+
readEntries();
|
|
1314
|
+
}
|
|
1315
|
+
return entryTable[entryName] || null;
|
|
1316
|
+
},
|
|
1317
|
+
/**
|
|
1318
|
+
* Adds the given entry to the entry list
|
|
1319
|
+
*
|
|
1320
|
+
* @param entry
|
|
1321
|
+
*/
|
|
1322
|
+
setEntry: function(entry) {
|
|
1323
|
+
if (!loadedEntries) {
|
|
1324
|
+
readEntries();
|
|
1325
|
+
}
|
|
1326
|
+
entryList.push(entry);
|
|
1327
|
+
entryTable[entry.entryName] = entry;
|
|
1328
|
+
mainHeader.totalEntries = entryList.length;
|
|
1329
|
+
},
|
|
1330
|
+
/**
|
|
1331
|
+
* Removes the entry with the given name from the entry list.
|
|
1332
|
+
*
|
|
1333
|
+
* If the entry is a directory, then all nested files and directories will be removed
|
|
1334
|
+
* @param entryName
|
|
1335
|
+
*/
|
|
1336
|
+
deleteEntry: function(entryName) {
|
|
1337
|
+
if (!loadedEntries) {
|
|
1338
|
+
readEntries();
|
|
1339
|
+
}
|
|
1340
|
+
var entry = entryTable[entryName];
|
|
1341
|
+
if (entry && entry.isDirectory) {
|
|
1342
|
+
var _self = this;
|
|
1343
|
+
this.getEntryChildren(entry).forEach(function(child) {
|
|
1344
|
+
if (child.entryName !== entryName) {
|
|
1345
|
+
_self.deleteEntry(child.entryName);
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
entryList.splice(entryList.indexOf(entry), 1);
|
|
1350
|
+
delete entryTable[entryName];
|
|
1351
|
+
mainHeader.totalEntries = entryList.length;
|
|
1352
|
+
},
|
|
1353
|
+
/**
|
|
1354
|
+
* Iterates and returns all nested files and directories of the given entry
|
|
1355
|
+
*
|
|
1356
|
+
* @param entry
|
|
1357
|
+
* @return Array
|
|
1358
|
+
*/
|
|
1359
|
+
getEntryChildren: function(entry) {
|
|
1360
|
+
if (!loadedEntries) {
|
|
1361
|
+
readEntries();
|
|
1362
|
+
}
|
|
1363
|
+
if (entry.isDirectory) {
|
|
1364
|
+
var list = [], name = entry.entryName, len = name.length;
|
|
1365
|
+
entryList.forEach(function(zipEntry) {
|
|
1366
|
+
if (zipEntry.entryName.substr(0, len) === name) {
|
|
1367
|
+
list.push(zipEntry);
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
return list;
|
|
1371
|
+
}
|
|
1372
|
+
return [];
|
|
1373
|
+
},
|
|
1374
|
+
/**
|
|
1375
|
+
* Returns the zip file
|
|
1376
|
+
*
|
|
1377
|
+
* @return Buffer
|
|
1378
|
+
*/
|
|
1379
|
+
compressToBuffer: function() {
|
|
1380
|
+
if (!loadedEntries) {
|
|
1381
|
+
readEntries();
|
|
1382
|
+
}
|
|
1383
|
+
if (entryList.length > 1) {
|
|
1384
|
+
entryList.sort(function(a, b) {
|
|
1385
|
+
var nameA = a.entryName.toLowerCase();
|
|
1386
|
+
var nameB = b.entryName.toLowerCase();
|
|
1387
|
+
if (nameA < nameB) {
|
|
1388
|
+
return -1;
|
|
1389
|
+
}
|
|
1390
|
+
if (nameA > nameB) {
|
|
1391
|
+
return 1;
|
|
1392
|
+
}
|
|
1393
|
+
return 0;
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
var totalSize = 0, dataBlock = [], entryHeaders = [], dindex = 0;
|
|
1397
|
+
mainHeader.size = 0;
|
|
1398
|
+
mainHeader.offset = 0;
|
|
1399
|
+
entryList.forEach(function(entry) {
|
|
1400
|
+
var compressedData = entry.getCompressedData();
|
|
1401
|
+
entry.header.offset = dindex;
|
|
1402
|
+
var dataHeader = entry.header.dataHeaderToBinary();
|
|
1403
|
+
var entryNameLen = entry.rawEntryName.length;
|
|
1404
|
+
var extra = entry.extra.toString();
|
|
1405
|
+
var postHeader = Buffer.alloc(entryNameLen + extra.length);
|
|
1406
|
+
entry.rawEntryName.copy(postHeader, 0);
|
|
1407
|
+
postHeader.fill(extra, entryNameLen);
|
|
1408
|
+
var dataLength = dataHeader.length + postHeader.length + compressedData.length;
|
|
1409
|
+
dindex += dataLength;
|
|
1410
|
+
dataBlock.push(dataHeader);
|
|
1411
|
+
dataBlock.push(postHeader);
|
|
1412
|
+
dataBlock.push(compressedData);
|
|
1413
|
+
var entryHeader = entry.packHeader();
|
|
1414
|
+
entryHeaders.push(entryHeader);
|
|
1415
|
+
mainHeader.size += entryHeader.length;
|
|
1416
|
+
totalSize += dataLength + entryHeader.length;
|
|
1417
|
+
});
|
|
1418
|
+
totalSize += mainHeader.mainHeaderSize;
|
|
1419
|
+
mainHeader.offset = dindex;
|
|
1420
|
+
dindex = 0;
|
|
1421
|
+
var outBuffer = Buffer.alloc(totalSize);
|
|
1422
|
+
dataBlock.forEach(function(content) {
|
|
1423
|
+
content.copy(outBuffer, dindex);
|
|
1424
|
+
dindex += content.length;
|
|
1425
|
+
});
|
|
1426
|
+
entryHeaders.forEach(function(content) {
|
|
1427
|
+
content.copy(outBuffer, dindex);
|
|
1428
|
+
dindex += content.length;
|
|
1429
|
+
});
|
|
1430
|
+
var mh = mainHeader.toBinary();
|
|
1431
|
+
if (_comment) {
|
|
1432
|
+
Buffer.from(_comment).copy(mh, Utils.Constants.ENDHDR);
|
|
1433
|
+
}
|
|
1434
|
+
mh.copy(outBuffer, dindex);
|
|
1435
|
+
return outBuffer;
|
|
1436
|
+
},
|
|
1437
|
+
toAsyncBuffer: function(onSuccess, onFail, onItemStart, onItemEnd) {
|
|
1438
|
+
if (!loadedEntries) {
|
|
1439
|
+
readEntries();
|
|
1440
|
+
}
|
|
1441
|
+
if (entryList.length > 1) {
|
|
1442
|
+
entryList.sort(function(a, b) {
|
|
1443
|
+
var nameA = a.entryName.toLowerCase();
|
|
1444
|
+
var nameB = b.entryName.toLowerCase();
|
|
1445
|
+
if (nameA > nameB) {
|
|
1446
|
+
return -1;
|
|
1447
|
+
}
|
|
1448
|
+
if (nameA < nameB) {
|
|
1449
|
+
return 1;
|
|
1450
|
+
}
|
|
1451
|
+
return 0;
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
var totalSize = 0, dataBlock = [], entryHeaders = [], dindex = 0;
|
|
1455
|
+
mainHeader.size = 0;
|
|
1456
|
+
mainHeader.offset = 0;
|
|
1457
|
+
var compress = function(entryList2) {
|
|
1458
|
+
var self = arguments.callee;
|
|
1459
|
+
if (entryList2.length) {
|
|
1460
|
+
var entry = entryList2.pop();
|
|
1461
|
+
var name = entry.entryName + entry.extra.toString();
|
|
1462
|
+
if (onItemStart) onItemStart(name);
|
|
1463
|
+
entry.getCompressedDataAsync(function(compressedData) {
|
|
1464
|
+
if (onItemEnd) onItemEnd(name);
|
|
1465
|
+
entry.header.offset = dindex;
|
|
1466
|
+
var dataHeader = entry.header.dataHeaderToBinary();
|
|
1467
|
+
var postHeader;
|
|
1468
|
+
try {
|
|
1469
|
+
postHeader = Buffer.alloc(name.length, name);
|
|
1470
|
+
} catch (e) {
|
|
1471
|
+
postHeader = new Buffer(name);
|
|
1472
|
+
}
|
|
1473
|
+
var dataLength = dataHeader.length + postHeader.length + compressedData.length;
|
|
1474
|
+
dindex += dataLength;
|
|
1475
|
+
dataBlock.push(dataHeader);
|
|
1476
|
+
dataBlock.push(postHeader);
|
|
1477
|
+
dataBlock.push(compressedData);
|
|
1478
|
+
var entryHeader = entry.packHeader();
|
|
1479
|
+
entryHeaders.push(entryHeader);
|
|
1480
|
+
mainHeader.size += entryHeader.length;
|
|
1481
|
+
totalSize += dataLength + entryHeader.length;
|
|
1482
|
+
if (entryList2.length) {
|
|
1483
|
+
self(entryList2);
|
|
1484
|
+
} else {
|
|
1485
|
+
totalSize += mainHeader.mainHeaderSize;
|
|
1486
|
+
mainHeader.offset = dindex;
|
|
1487
|
+
dindex = 0;
|
|
1488
|
+
var outBuffer = Buffer.alloc(totalSize);
|
|
1489
|
+
dataBlock.forEach(function(content) {
|
|
1490
|
+
content.copy(outBuffer, dindex);
|
|
1491
|
+
dindex += content.length;
|
|
1492
|
+
});
|
|
1493
|
+
entryHeaders.forEach(function(content) {
|
|
1494
|
+
content.copy(outBuffer, dindex);
|
|
1495
|
+
dindex += content.length;
|
|
1496
|
+
});
|
|
1497
|
+
var mh = mainHeader.toBinary();
|
|
1498
|
+
if (_comment) {
|
|
1499
|
+
_comment.copy(mh, Utils.Constants.ENDHDR);
|
|
1500
|
+
}
|
|
1501
|
+
mh.copy(outBuffer, dindex);
|
|
1502
|
+
onSuccess(outBuffer);
|
|
1503
|
+
}
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
compress(entryList);
|
|
1508
|
+
}
|
|
1509
|
+
};
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1514
|
+
// ../../node_modules/adm-zip/adm-zip.js
|
|
1515
|
+
var require_adm_zip = __commonJS({
|
|
1516
|
+
"../../node_modules/adm-zip/adm-zip.js"(exports, module) {
|
|
1517
|
+
var Utils = require_util();
|
|
1518
|
+
var fs10 = Utils.FileSystem.require();
|
|
1519
|
+
var pth = __require("path");
|
|
1520
|
+
fs10.existsSync = fs10.existsSync || pth.existsSync;
|
|
1521
|
+
var ZipEntry = require_zipEntry();
|
|
1522
|
+
var ZipFile = require_zipFile();
|
|
1523
|
+
var isWin = /^win/.test(process.platform);
|
|
1524
|
+
module.exports = function(input) {
|
|
1525
|
+
var _zip = void 0, _filename = "";
|
|
1526
|
+
if (input && typeof input === "string") {
|
|
1527
|
+
if (fs10.existsSync(input)) {
|
|
1528
|
+
_filename = input;
|
|
1529
|
+
_zip = new ZipFile(input, Utils.Constants.FILE);
|
|
1530
|
+
} else {
|
|
1531
|
+
throw new Error(Utils.Errors.INVALID_FILENAME);
|
|
1532
|
+
}
|
|
1533
|
+
} else if (input && Buffer.isBuffer(input)) {
|
|
1534
|
+
_zip = new ZipFile(input, Utils.Constants.BUFFER);
|
|
1535
|
+
} else {
|
|
1536
|
+
_zip = new ZipFile(null, Utils.Constants.NONE);
|
|
1537
|
+
}
|
|
1538
|
+
function sanitize(prefix, name) {
|
|
1539
|
+
prefix = pth.resolve(pth.normalize(prefix));
|
|
1540
|
+
var parts = name.split("/");
|
|
1541
|
+
for (var i = 0, l = parts.length; i < l; i++) {
|
|
1542
|
+
var path12 = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep)));
|
|
1543
|
+
if (path12.indexOf(prefix) === 0) {
|
|
1544
|
+
return path12;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return pth.normalize(pth.join(prefix, pth.basename(name)));
|
|
1548
|
+
}
|
|
1549
|
+
function getEntry(entry) {
|
|
1550
|
+
if (entry && _zip) {
|
|
1551
|
+
var item;
|
|
1552
|
+
if (typeof entry === "string")
|
|
1553
|
+
item = _zip.getEntry(entry);
|
|
1554
|
+
if (typeof entry === "object" && typeof entry.entryName !== "undefined" && typeof entry.header !== "undefined")
|
|
1555
|
+
item = _zip.getEntry(entry.entryName);
|
|
1556
|
+
if (item) {
|
|
1557
|
+
return item;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1562
|
+
return {
|
|
1563
|
+
/**
|
|
1564
|
+
* Extracts the given entry from the archive and returns the content as a Buffer object
|
|
1565
|
+
* @param entry ZipEntry object or String with the full path of the entry
|
|
1566
|
+
*
|
|
1567
|
+
* @return Buffer or Null in case of error
|
|
1568
|
+
*/
|
|
1569
|
+
readFile: function(entry) {
|
|
1570
|
+
var item = getEntry(entry);
|
|
1571
|
+
return item && item.getData() || null;
|
|
1572
|
+
},
|
|
1573
|
+
/**
|
|
1574
|
+
* Asynchronous readFile
|
|
1575
|
+
* @param entry ZipEntry object or String with the full path of the entry
|
|
1576
|
+
* @param callback
|
|
1577
|
+
*
|
|
1578
|
+
* @return Buffer or Null in case of error
|
|
1579
|
+
*/
|
|
1580
|
+
readFileAsync: function(entry, callback) {
|
|
1581
|
+
var item = getEntry(entry);
|
|
1582
|
+
if (item) {
|
|
1583
|
+
item.getDataAsync(callback);
|
|
1584
|
+
} else {
|
|
1585
|
+
callback(null, "getEntry failed for:" + entry);
|
|
1586
|
+
}
|
|
1587
|
+
},
|
|
1588
|
+
/**
|
|
1589
|
+
* Extracts the given entry from the archive and returns the content as plain text in the given encoding
|
|
1590
|
+
* @param entry ZipEntry object or String with the full path of the entry
|
|
1591
|
+
* @param encoding Optional. If no encoding is specified utf8 is used
|
|
1592
|
+
*
|
|
1593
|
+
* @return String
|
|
1594
|
+
*/
|
|
1595
|
+
readAsText: function(entry, encoding) {
|
|
1596
|
+
var item = getEntry(entry);
|
|
1597
|
+
if (item) {
|
|
1598
|
+
var data = item.getData();
|
|
1599
|
+
if (data && data.length) {
|
|
1600
|
+
return data.toString(encoding || "utf8");
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
return "";
|
|
1604
|
+
},
|
|
1605
|
+
/**
|
|
1606
|
+
* Asynchronous readAsText
|
|
1607
|
+
* @param entry ZipEntry object or String with the full path of the entry
|
|
1608
|
+
* @param callback
|
|
1609
|
+
* @param encoding Optional. If no encoding is specified utf8 is used
|
|
1610
|
+
*
|
|
1611
|
+
* @return String
|
|
1612
|
+
*/
|
|
1613
|
+
readAsTextAsync: function(entry, callback, encoding) {
|
|
1614
|
+
var item = getEntry(entry);
|
|
1615
|
+
if (item) {
|
|
1616
|
+
item.getDataAsync(function(data, err) {
|
|
1617
|
+
if (err) {
|
|
1618
|
+
callback(data, err);
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
if (data && data.length) {
|
|
1622
|
+
callback(data.toString(encoding || "utf8"));
|
|
1623
|
+
} else {
|
|
1624
|
+
callback("");
|
|
1625
|
+
}
|
|
1626
|
+
});
|
|
1627
|
+
} else {
|
|
1628
|
+
callback("");
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
/**
|
|
1632
|
+
* Remove the entry from the file or the entry and all it's nested directories and files if the given entry is a directory
|
|
1633
|
+
*
|
|
1634
|
+
* @param entry
|
|
1635
|
+
*/
|
|
1636
|
+
deleteFile: function(entry) {
|
|
1637
|
+
var item = getEntry(entry);
|
|
1638
|
+
if (item) {
|
|
1639
|
+
_zip.deleteEntry(item.entryName);
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
/**
|
|
1643
|
+
* Adds a comment to the zip. The zip must be rewritten after adding the comment.
|
|
1644
|
+
*
|
|
1645
|
+
* @param comment
|
|
1646
|
+
*/
|
|
1647
|
+
addZipComment: function(comment) {
|
|
1648
|
+
_zip.comment = comment;
|
|
1649
|
+
},
|
|
1650
|
+
/**
|
|
1651
|
+
* Returns the zip comment
|
|
1652
|
+
*
|
|
1653
|
+
* @return String
|
|
1654
|
+
*/
|
|
1655
|
+
getZipComment: function() {
|
|
1656
|
+
return _zip.comment || "";
|
|
1657
|
+
},
|
|
1658
|
+
/**
|
|
1659
|
+
* Adds a comment to a specified zipEntry. The zip must be rewritten after adding the comment
|
|
1660
|
+
* The comment cannot exceed 65535 characters in length
|
|
1661
|
+
*
|
|
1662
|
+
* @param entry
|
|
1663
|
+
* @param comment
|
|
1664
|
+
*/
|
|
1665
|
+
addZipEntryComment: function(entry, comment) {
|
|
1666
|
+
var item = getEntry(entry);
|
|
1667
|
+
if (item) {
|
|
1668
|
+
item.comment = comment;
|
|
1669
|
+
}
|
|
1670
|
+
},
|
|
1671
|
+
/**
|
|
1672
|
+
* Returns the comment of the specified entry
|
|
1673
|
+
*
|
|
1674
|
+
* @param entry
|
|
1675
|
+
* @return String
|
|
1676
|
+
*/
|
|
1677
|
+
getZipEntryComment: function(entry) {
|
|
1678
|
+
var item = getEntry(entry);
|
|
1679
|
+
if (item) {
|
|
1680
|
+
return item.comment || "";
|
|
1681
|
+
}
|
|
1682
|
+
return "";
|
|
1683
|
+
},
|
|
1684
|
+
/**
|
|
1685
|
+
* Updates the content of an existing entry inside the archive. The zip must be rewritten after updating the content
|
|
1686
|
+
*
|
|
1687
|
+
* @param entry
|
|
1688
|
+
* @param content
|
|
1689
|
+
*/
|
|
1690
|
+
updateFile: function(entry, content) {
|
|
1691
|
+
var item = getEntry(entry);
|
|
1692
|
+
if (item) {
|
|
1693
|
+
item.setData(content);
|
|
1694
|
+
}
|
|
1695
|
+
},
|
|
1696
|
+
/**
|
|
1697
|
+
* Adds a file from the disk to the archive
|
|
1698
|
+
*
|
|
1699
|
+
* @param localPath File to add to zip
|
|
1700
|
+
* @param zipPath Optional path inside the zip
|
|
1701
|
+
* @param zipName Optional name for the file
|
|
1702
|
+
*/
|
|
1703
|
+
addLocalFile: function(localPath, zipPath, zipName) {
|
|
1704
|
+
if (fs10.existsSync(localPath)) {
|
|
1705
|
+
if (zipPath) {
|
|
1706
|
+
zipPath = zipPath.split("\\").join("/");
|
|
1707
|
+
if (zipPath.charAt(zipPath.length - 1) !== "/") {
|
|
1708
|
+
zipPath += "/";
|
|
1709
|
+
}
|
|
1710
|
+
} else {
|
|
1711
|
+
zipPath = "";
|
|
1712
|
+
}
|
|
1713
|
+
var p = localPath.split("\\").join("/").split("/").pop();
|
|
1714
|
+
if (zipName) {
|
|
1715
|
+
this.addFile(zipPath + zipName, fs10.readFileSync(localPath), "", 0);
|
|
1716
|
+
} else {
|
|
1717
|
+
this.addFile(zipPath + p, fs10.readFileSync(localPath), "", 0);
|
|
1718
|
+
}
|
|
1719
|
+
} else {
|
|
1720
|
+
throw new Error(Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath));
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1723
|
+
/**
|
|
1724
|
+
* Adds a local directory and all its nested files and directories to the archive
|
|
1725
|
+
*
|
|
1726
|
+
* @param localPath
|
|
1727
|
+
* @param zipPath optional path inside zip
|
|
1728
|
+
* @param filter optional RegExp or Function if files match will
|
|
1729
|
+
* be included.
|
|
1730
|
+
*/
|
|
1731
|
+
addLocalFolder: function(localPath, zipPath, filter) {
|
|
1732
|
+
if (filter === void 0) {
|
|
1733
|
+
filter = function() {
|
|
1734
|
+
return true;
|
|
1735
|
+
};
|
|
1736
|
+
} else if (filter instanceof RegExp) {
|
|
1737
|
+
filter = /* @__PURE__ */ (function(filter2) {
|
|
1738
|
+
return function(filename) {
|
|
1739
|
+
return filter2.test(filename);
|
|
1740
|
+
};
|
|
1741
|
+
})(filter);
|
|
1742
|
+
}
|
|
1743
|
+
if (zipPath) {
|
|
1744
|
+
zipPath = zipPath.split("\\").join("/");
|
|
1745
|
+
if (zipPath.charAt(zipPath.length - 1) !== "/") {
|
|
1746
|
+
zipPath += "/";
|
|
1747
|
+
}
|
|
1748
|
+
} else {
|
|
1749
|
+
zipPath = "";
|
|
1750
|
+
}
|
|
1751
|
+
localPath = pth.normalize(localPath);
|
|
1752
|
+
localPath = localPath.split("\\").join("/");
|
|
1753
|
+
if (localPath.charAt(localPath.length - 1) !== "/")
|
|
1754
|
+
localPath += "/";
|
|
1755
|
+
if (fs10.existsSync(localPath)) {
|
|
1756
|
+
var items = Utils.findFiles(localPath), self = this;
|
|
1757
|
+
if (items.length) {
|
|
1758
|
+
items.forEach(function(path12) {
|
|
1759
|
+
var p = path12.split("\\").join("/").replace(new RegExp(localPath.replace(/(\(|\)|\$)/g, "\\$1"), "i"), "");
|
|
1760
|
+
if (filter(p)) {
|
|
1761
|
+
if (p.charAt(p.length - 1) !== "/") {
|
|
1762
|
+
self.addFile(zipPath + p, fs10.readFileSync(path12), "", 0);
|
|
1763
|
+
} else {
|
|
1764
|
+
self.addFile(zipPath + p, Buffer.alloc(0), "", 0);
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
} else {
|
|
1770
|
+
throw new Error(Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath));
|
|
1771
|
+
}
|
|
1772
|
+
},
|
|
1773
|
+
/**
|
|
1774
|
+
* Asynchronous addLocalFile
|
|
1775
|
+
* @param localPath
|
|
1776
|
+
* @param callback
|
|
1777
|
+
* @param zipPath optional path inside zip
|
|
1778
|
+
* @param filter optional RegExp or Function if files match will
|
|
1779
|
+
* be included.
|
|
1780
|
+
*/
|
|
1781
|
+
addLocalFolderAsync: function(localPath, callback, zipPath, filter) {
|
|
1782
|
+
if (filter === void 0) {
|
|
1783
|
+
filter = function() {
|
|
1784
|
+
return true;
|
|
1785
|
+
};
|
|
1786
|
+
} else if (filter instanceof RegExp) {
|
|
1787
|
+
filter = /* @__PURE__ */ (function(filter2) {
|
|
1788
|
+
return function(filename) {
|
|
1789
|
+
return filter2.test(filename);
|
|
1790
|
+
};
|
|
1791
|
+
})(filter);
|
|
1792
|
+
}
|
|
1793
|
+
if (zipPath) {
|
|
1794
|
+
zipPath = zipPath.split("\\").join("/");
|
|
1795
|
+
if (zipPath.charAt(zipPath.length - 1) !== "/") {
|
|
1796
|
+
zipPath += "/";
|
|
1797
|
+
}
|
|
1798
|
+
} else {
|
|
1799
|
+
zipPath = "";
|
|
1800
|
+
}
|
|
1801
|
+
localPath = pth.normalize(localPath);
|
|
1802
|
+
localPath = localPath.split("\\").join("/");
|
|
1803
|
+
if (localPath.charAt(localPath.length - 1) !== "/")
|
|
1804
|
+
localPath += "/";
|
|
1805
|
+
var self = this;
|
|
1806
|
+
fs10.open(localPath, "r", function(err, fd) {
|
|
1807
|
+
if (err && err.code === "ENOENT") {
|
|
1808
|
+
callback(void 0, Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath));
|
|
1809
|
+
} else if (err) {
|
|
1810
|
+
callback(void 0, err);
|
|
1811
|
+
} else {
|
|
1812
|
+
var items = Utils.findFiles(localPath);
|
|
1813
|
+
var i = -1;
|
|
1814
|
+
var next = function() {
|
|
1815
|
+
i += 1;
|
|
1816
|
+
if (i < items.length) {
|
|
1817
|
+
var p = items[i].split("\\").join("/").replace(new RegExp(localPath.replace(/(\(|\))/g, "\\$1"), "i"), "");
|
|
1818
|
+
p = p.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\x20-\x7E]/g, "");
|
|
1819
|
+
if (filter(p)) {
|
|
1820
|
+
if (p.charAt(p.length - 1) !== "/") {
|
|
1821
|
+
fs10.readFile(items[i], function(err2, data) {
|
|
1822
|
+
if (err2) {
|
|
1823
|
+
callback(void 0, err2);
|
|
1824
|
+
} else {
|
|
1825
|
+
self.addFile(zipPath + p, data, "", 0);
|
|
1826
|
+
next();
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
} else {
|
|
1830
|
+
self.addFile(zipPath + p, Buffer.alloc(0), "", 0);
|
|
1831
|
+
next();
|
|
1832
|
+
}
|
|
1833
|
+
} else {
|
|
1834
|
+
next();
|
|
1835
|
+
}
|
|
1836
|
+
} else {
|
|
1837
|
+
callback(true, void 0);
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
next();
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
},
|
|
1844
|
+
/**
|
|
1845
|
+
* Allows you to create a entry (file or directory) in the zip file.
|
|
1846
|
+
* If you want to create a directory the entryName must end in / and a null buffer should be provided.
|
|
1847
|
+
* Comment and attributes are optional
|
|
1848
|
+
*
|
|
1849
|
+
* @param entryName
|
|
1850
|
+
* @param content
|
|
1851
|
+
* @param comment
|
|
1852
|
+
* @param attr
|
|
1853
|
+
*/
|
|
1854
|
+
addFile: function(entryName, content, comment, attr) {
|
|
1855
|
+
var entry = new ZipEntry();
|
|
1856
|
+
entry.entryName = entryName;
|
|
1857
|
+
entry.comment = comment || "";
|
|
1858
|
+
if (!attr) {
|
|
1859
|
+
if (entry.isDirectory) {
|
|
1860
|
+
attr = 16877 << 16 | 16;
|
|
1861
|
+
} else {
|
|
1862
|
+
attr = 420 << 16;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
entry.attr = attr;
|
|
1866
|
+
entry.setData(content);
|
|
1867
|
+
_zip.setEntry(entry);
|
|
1868
|
+
},
|
|
1869
|
+
/**
|
|
1870
|
+
* Returns an array of ZipEntry objects representing the files and folders inside the archive
|
|
1871
|
+
*
|
|
1872
|
+
* @return Array
|
|
1873
|
+
*/
|
|
1874
|
+
getEntries: function() {
|
|
1875
|
+
if (_zip) {
|
|
1876
|
+
return _zip.entries;
|
|
1877
|
+
} else {
|
|
1878
|
+
return [];
|
|
1879
|
+
}
|
|
1880
|
+
},
|
|
1881
|
+
/**
|
|
1882
|
+
* Returns a ZipEntry object representing the file or folder specified by ``name``.
|
|
1883
|
+
*
|
|
1884
|
+
* @param name
|
|
1885
|
+
* @return ZipEntry
|
|
1886
|
+
*/
|
|
1887
|
+
getEntry: function(name) {
|
|
1888
|
+
return getEntry(name);
|
|
1889
|
+
},
|
|
1890
|
+
getEntryCount: function() {
|
|
1891
|
+
return _zip.getEntryCount();
|
|
1892
|
+
},
|
|
1893
|
+
forEach: function(callback) {
|
|
1894
|
+
return _zip.forEach(callback);
|
|
1895
|
+
},
|
|
1896
|
+
/**
|
|
1897
|
+
* Extracts the given entry to the given targetPath
|
|
1898
|
+
* If the entry is a directory inside the archive, the entire directory and it's subdirectories will be extracted
|
|
1899
|
+
*
|
|
1900
|
+
* @param entry ZipEntry object or String with the full path of the entry
|
|
1901
|
+
* @param targetPath Target folder where to write the file
|
|
1902
|
+
* @param maintainEntryPath If maintainEntryPath is true and the entry is inside a folder, the entry folder
|
|
1903
|
+
* will be created in targetPath as well. Default is TRUE
|
|
1904
|
+
* @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
|
|
1905
|
+
* Default is FALSE
|
|
1906
|
+
*
|
|
1907
|
+
* @return Boolean
|
|
1908
|
+
*/
|
|
1909
|
+
extractEntryTo: function(entry, targetPath, maintainEntryPath, overwrite) {
|
|
1910
|
+
overwrite = overwrite || false;
|
|
1911
|
+
maintainEntryPath = typeof maintainEntryPath === "undefined" ? true : maintainEntryPath;
|
|
1912
|
+
var item = getEntry(entry);
|
|
1913
|
+
if (!item) {
|
|
1914
|
+
throw new Error(Utils.Errors.NO_ENTRY);
|
|
1915
|
+
}
|
|
1916
|
+
var entryName = item.entryName;
|
|
1917
|
+
var target = sanitize(targetPath, maintainEntryPath ? entryName : pth.basename(entryName));
|
|
1918
|
+
if (item.isDirectory) {
|
|
1919
|
+
target = pth.resolve(target, "..");
|
|
1920
|
+
var children = _zip.getEntryChildren(item);
|
|
1921
|
+
children.forEach(function(child) {
|
|
1922
|
+
if (child.isDirectory) return;
|
|
1923
|
+
var content2 = child.getData();
|
|
1924
|
+
if (!content2) {
|
|
1925
|
+
throw new Error(Utils.Errors.CANT_EXTRACT_FILE);
|
|
1926
|
+
}
|
|
1927
|
+
var childName = sanitize(targetPath, maintainEntryPath ? child.entryName : pth.basename(child.entryName));
|
|
1928
|
+
Utils.writeFileTo(childName, content2, overwrite);
|
|
1929
|
+
});
|
|
1930
|
+
return true;
|
|
1931
|
+
}
|
|
1932
|
+
var content = item.getData();
|
|
1933
|
+
if (!content) throw new Error(Utils.Errors.CANT_EXTRACT_FILE);
|
|
1934
|
+
if (fs10.existsSync(target) && !overwrite) {
|
|
1935
|
+
throw new Error(Utils.Errors.CANT_OVERRIDE);
|
|
1936
|
+
}
|
|
1937
|
+
Utils.writeFileTo(target, content, overwrite);
|
|
1938
|
+
return true;
|
|
1939
|
+
},
|
|
1940
|
+
/**
|
|
1941
|
+
* Test the archive
|
|
1942
|
+
*
|
|
1943
|
+
*/
|
|
1944
|
+
test: function() {
|
|
1945
|
+
if (!_zip) {
|
|
1946
|
+
return false;
|
|
1947
|
+
}
|
|
1948
|
+
for (var entry in _zip.entries) {
|
|
1949
|
+
try {
|
|
1950
|
+
if (entry.isDirectory) {
|
|
1951
|
+
continue;
|
|
1952
|
+
}
|
|
1953
|
+
var content = _zip.entries[entry].getData();
|
|
1954
|
+
if (!content) {
|
|
1955
|
+
return false;
|
|
1956
|
+
}
|
|
1957
|
+
} catch (err) {
|
|
1958
|
+
return false;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
return true;
|
|
1962
|
+
},
|
|
1963
|
+
/**
|
|
1964
|
+
* Extracts the entire archive to the given location
|
|
1965
|
+
*
|
|
1966
|
+
* @param targetPath Target location
|
|
1967
|
+
* @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
|
|
1968
|
+
* Default is FALSE
|
|
1969
|
+
*/
|
|
1970
|
+
extractAllTo: function(targetPath, overwrite) {
|
|
1971
|
+
overwrite = overwrite || false;
|
|
1972
|
+
if (!_zip) {
|
|
1973
|
+
throw new Error(Utils.Errors.NO_ZIP);
|
|
1974
|
+
}
|
|
1975
|
+
_zip.entries.forEach(function(entry) {
|
|
1976
|
+
var entryName = sanitize(targetPath, entry.entryName.toString());
|
|
1977
|
+
if (entry.isDirectory) {
|
|
1978
|
+
Utils.makeDir(entryName);
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
var content = entry.getData();
|
|
1982
|
+
if (!content) {
|
|
1983
|
+
throw new Error(Utils.Errors.CANT_EXTRACT_FILE);
|
|
1984
|
+
}
|
|
1985
|
+
Utils.writeFileTo(entryName, content, overwrite);
|
|
1986
|
+
try {
|
|
1987
|
+
fs10.utimesSync(entryName, entry.header.time, entry.header.time);
|
|
1988
|
+
} catch (err) {
|
|
1989
|
+
throw new Error(Utils.Errors.CANT_EXTRACT_FILE);
|
|
1990
|
+
}
|
|
1991
|
+
});
|
|
1992
|
+
},
|
|
1993
|
+
/**
|
|
1994
|
+
* Asynchronous extractAllTo
|
|
1995
|
+
*
|
|
1996
|
+
* @param targetPath Target location
|
|
1997
|
+
* @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
|
|
1998
|
+
* Default is FALSE
|
|
1999
|
+
* @param callback
|
|
2000
|
+
*/
|
|
2001
|
+
extractAllToAsync: function(targetPath, overwrite, callback) {
|
|
2002
|
+
if (!callback) {
|
|
2003
|
+
callback = function() {
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
overwrite = overwrite || false;
|
|
2007
|
+
if (!_zip) {
|
|
2008
|
+
callback(new Error(Utils.Errors.NO_ZIP));
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
var entries = _zip.entries;
|
|
2012
|
+
var i = entries.length;
|
|
2013
|
+
entries.forEach(function(entry) {
|
|
2014
|
+
if (i <= 0) return;
|
|
2015
|
+
var entryName = pth.normalize(entry.entryName.toString());
|
|
2016
|
+
if (entry.isDirectory) {
|
|
2017
|
+
Utils.makeDir(sanitize(targetPath, entryName));
|
|
2018
|
+
if (--i === 0)
|
|
2019
|
+
callback(void 0);
|
|
2020
|
+
return;
|
|
2021
|
+
}
|
|
2022
|
+
entry.getDataAsync(function(content, err) {
|
|
2023
|
+
if (i <= 0) return;
|
|
2024
|
+
if (err) {
|
|
2025
|
+
callback(new Error(err));
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
if (!content) {
|
|
2029
|
+
i = 0;
|
|
2030
|
+
callback(new Error(Utils.Errors.CANT_EXTRACT_FILE));
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
Utils.writeFileToAsync(sanitize(targetPath, entryName), content, overwrite, function(succ) {
|
|
2034
|
+
try {
|
|
2035
|
+
fs10.utimesSync(pth.resolve(targetPath, entryName), entry.header.time, entry.header.time);
|
|
2036
|
+
} catch (err2) {
|
|
2037
|
+
callback(new Error("Unable to set utimes"));
|
|
2038
|
+
}
|
|
2039
|
+
if (i <= 0) return;
|
|
2040
|
+
if (!succ) {
|
|
2041
|
+
i = 0;
|
|
2042
|
+
callback(new Error("Unable to write"));
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
if (--i === 0)
|
|
2046
|
+
callback(void 0);
|
|
2047
|
+
});
|
|
2048
|
+
});
|
|
2049
|
+
});
|
|
2050
|
+
},
|
|
2051
|
+
/**
|
|
2052
|
+
* 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
|
|
2053
|
+
*
|
|
2054
|
+
* @param targetFileName
|
|
2055
|
+
* @param callback
|
|
2056
|
+
*/
|
|
2057
|
+
writeZip: function(targetFileName, callback) {
|
|
2058
|
+
if (arguments.length === 1) {
|
|
2059
|
+
if (typeof targetFileName === "function") {
|
|
2060
|
+
callback = targetFileName;
|
|
2061
|
+
targetFileName = "";
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
if (!targetFileName && _filename) {
|
|
2065
|
+
targetFileName = _filename;
|
|
2066
|
+
}
|
|
2067
|
+
if (!targetFileName) return;
|
|
2068
|
+
var zipData = _zip.compressToBuffer();
|
|
2069
|
+
if (zipData) {
|
|
2070
|
+
var ok = Utils.writeFileTo(targetFileName, zipData, true);
|
|
2071
|
+
if (typeof callback === "function") callback(!ok ? new Error("failed") : null, "");
|
|
2072
|
+
}
|
|
2073
|
+
},
|
|
2074
|
+
/**
|
|
2075
|
+
* Returns the content of the entire zip file as a Buffer object
|
|
2076
|
+
*
|
|
2077
|
+
* @return Buffer
|
|
2078
|
+
*/
|
|
2079
|
+
toBuffer: function(onSuccess, onFail, onItemStart, onItemEnd) {
|
|
2080
|
+
this.valueOf = 2;
|
|
2081
|
+
if (typeof onSuccess === "function") {
|
|
2082
|
+
_zip.toAsyncBuffer(onSuccess, onFail, onItemStart, onItemEnd);
|
|
2083
|
+
return null;
|
|
2084
|
+
}
|
|
2085
|
+
return _zip.compressToBuffer();
|
|
2086
|
+
}
|
|
2087
|
+
};
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
|
|
1
2092
|
// src/index.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2093
|
+
import fs9 from "node:fs";
|
|
2094
|
+
import path11 from "node:path";
|
|
4
2095
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5
2096
|
import os4 from "node:os";
|
|
6
2097
|
|
|
@@ -101,12 +2192,11 @@ var ActiveSkills = class {
|
|
|
101
2192
|
};
|
|
102
2193
|
|
|
103
2194
|
// src/updater.ts
|
|
2195
|
+
var import_adm_zip = __toESM(require_adm_zip(), 1);
|
|
104
2196
|
import fs3 from "node:fs/promises";
|
|
105
2197
|
import fsSync from "node:fs";
|
|
106
2198
|
import path3 from "node:path";
|
|
107
2199
|
import os2 from "node:os";
|
|
108
|
-
import { execFile } from "node:child_process";
|
|
109
|
-
import { promisify } from "node:util";
|
|
110
2200
|
import { randomUUID, createHash } from "node:crypto";
|
|
111
2201
|
|
|
112
2202
|
// src/skill-version.ts
|
|
@@ -139,14 +2229,27 @@ function parseSkillVersion(content) {
|
|
|
139
2229
|
}
|
|
140
2230
|
|
|
141
2231
|
// src/updater.ts
|
|
142
|
-
var execFileAsync = promisify(execFile);
|
|
143
2232
|
var ATTEMPT_COOLDOWN_MS = 30 * 60 * 1e3;
|
|
144
2233
|
function skillIdentityHash(code, version) {
|
|
145
2234
|
return createHash("sha256").update(`${code} ${code} ${version}`).digest("hex");
|
|
146
2235
|
}
|
|
147
2236
|
async function systemUnzip(zipPath, destDir) {
|
|
148
2237
|
await fs3.mkdir(destDir, { recursive: true });
|
|
149
|
-
|
|
2238
|
+
const destRoot = path3.resolve(destDir);
|
|
2239
|
+
const zip = new import_adm_zip.default(zipPath);
|
|
2240
|
+
for (const entry of zip.getEntries()) {
|
|
2241
|
+
const normalizedName = entry.entryName.replace(/\\/g, "/");
|
|
2242
|
+
const outPath = path3.resolve(destRoot, normalizedName);
|
|
2243
|
+
if (outPath !== destRoot && !outPath.startsWith(destRoot + path3.sep)) {
|
|
2244
|
+
throw new Error(`ZIP \u5305\u542B\u975E\u6CD5\u8DEF\u5F84: ${entry.entryName}`);
|
|
2245
|
+
}
|
|
2246
|
+
if (entry.isDirectory) {
|
|
2247
|
+
await fs3.mkdir(outPath, { recursive: true });
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
await fs3.mkdir(path3.dirname(outPath), { recursive: true });
|
|
2251
|
+
await fs3.writeFile(outPath, entry.getData());
|
|
2252
|
+
}
|
|
150
2253
|
}
|
|
151
2254
|
var SkillUpdater = class {
|
|
152
2255
|
getConfig;
|
|
@@ -331,6 +2434,25 @@ var SkillUpdater = class {
|
|
|
331
2434
|
}
|
|
332
2435
|
return void 0;
|
|
333
2436
|
}
|
|
2437
|
+
/** 在解压目录里定位专家根目录;专家包根必须同时包含 AGENTS.md 和 SOUL.md。 */
|
|
2438
|
+
async locateExpertRoot(dir, depth) {
|
|
2439
|
+
if (depth > 2) return void 0;
|
|
2440
|
+
let entries;
|
|
2441
|
+
try {
|
|
2442
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
2443
|
+
} catch {
|
|
2444
|
+
return void 0;
|
|
2445
|
+
}
|
|
2446
|
+
const files = new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name));
|
|
2447
|
+
if (files.has("AGENTS.md") && files.has("SOUL.md")) return dir;
|
|
2448
|
+
for (const entry of entries) {
|
|
2449
|
+
if (entry.isDirectory()) {
|
|
2450
|
+
const found = await this.locateExpertRoot(path3.join(dir, entry.name), depth + 1);
|
|
2451
|
+
if (found) return found;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
return void 0;
|
|
2455
|
+
}
|
|
334
2456
|
/**
|
|
335
2457
|
* 直接覆盖、不备份,但保证「不丢数据」:
|
|
336
2458
|
* 先把新内容暂存到同级临时目录 → 旧目录改名挪开 → 新内容 rename 换入 → 删掉挪开的旧目录。
|
|
@@ -394,37 +2516,114 @@ var SkillUpdater = class {
|
|
|
394
2516
|
});
|
|
395
2517
|
}
|
|
396
2518
|
}
|
|
2519
|
+
async installExpertZipFromUrl(url, targetDir) {
|
|
2520
|
+
const work = path3.join(this.tmpDir, `slp-expert-${randomUUID()}`);
|
|
2521
|
+
await fs3.mkdir(work, { recursive: true });
|
|
2522
|
+
try {
|
|
2523
|
+
const zipPath = path3.join(work, "pkg.zip");
|
|
2524
|
+
const res = await this.fetchImpl(url);
|
|
2525
|
+
if (!res.ok) return { success: false, message: `\u4E0B\u8F7D\u5931\u8D25: HTTP ${res.status}` };
|
|
2526
|
+
await fs3.writeFile(zipPath, Buffer.from(await res.arrayBuffer()));
|
|
2527
|
+
const staging = path3.join(work, "staging");
|
|
2528
|
+
await this.unzip(zipPath, staging);
|
|
2529
|
+
const expertRoot = await this.locateExpertRoot(staging, 0);
|
|
2530
|
+
if (!expertRoot) {
|
|
2531
|
+
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" };
|
|
2532
|
+
}
|
|
2533
|
+
await this.replaceDir(expertRoot, targetDir);
|
|
2534
|
+
return { success: true, message: "\u5B89\u88C5\u6210\u529F" };
|
|
2535
|
+
} catch (err) {
|
|
2536
|
+
return { success: false, message: `\u6267\u884C\u51FA\u9519: ${err.message}` };
|
|
2537
|
+
} finally {
|
|
2538
|
+
await fs3.rm(work, { recursive: true, force: true }).catch(() => {
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
397
2542
|
async manualInstall(options) {
|
|
398
|
-
const { code, force, targetDir } = options;
|
|
2543
|
+
const { code, force, targetDir, additionalTargetDirs = [], trace } = options;
|
|
399
2544
|
let { url, version } = options;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
2545
|
+
const startedAt = Date.now();
|
|
2546
|
+
let currentStage = "install.start";
|
|
2547
|
+
let work;
|
|
2548
|
+
const emit = (stage, data) => {
|
|
2549
|
+
currentStage = stage;
|
|
2550
|
+
try {
|
|
2551
|
+
trace?.(stage, data);
|
|
2552
|
+
} catch {
|
|
404
2553
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
await fs3.mkdir(work, { recursive: true });
|
|
2554
|
+
};
|
|
2555
|
+
emit("install.start", {
|
|
2556
|
+
code,
|
|
2557
|
+
version: version || "latest",
|
|
2558
|
+
force,
|
|
2559
|
+
hasDirectUrl: Boolean(url),
|
|
2560
|
+
targetCount: 1 + additionalTargetDirs.length
|
|
2561
|
+
});
|
|
414
2562
|
try {
|
|
2563
|
+
if (!code || code === "." || code === ".." || code.includes("/") || code.includes("\\") || code.includes("\0") || path3.basename(code) !== code) {
|
|
2564
|
+
const message = `\u975E\u6CD5\u7684 Skill code: ${code}`;
|
|
2565
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
2566
|
+
return { success: false, message };
|
|
2567
|
+
}
|
|
2568
|
+
if (!url) {
|
|
2569
|
+
const lookupStartedAt = Date.now();
|
|
2570
|
+
emit("download_url.lookup.start", { code, version: version || "latest" });
|
|
2571
|
+
const dl = await this.fetchDownloadUrl(code, version || "latest");
|
|
2572
|
+
if (!dl?.url) {
|
|
2573
|
+
const message = `\u65E0\u6CD5\u83B7\u53D6\u6280\u80FD ${code} \u7684\u4E0B\u8F7D\u5730\u5740`;
|
|
2574
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
2575
|
+
return { success: false, message };
|
|
2576
|
+
}
|
|
2577
|
+
url = dl.url;
|
|
2578
|
+
version = dl.version || version;
|
|
2579
|
+
emit("download_url.lookup.completed", {
|
|
2580
|
+
version: version || "latest",
|
|
2581
|
+
url,
|
|
2582
|
+
elapsedMs: Date.now() - lookupStartedAt
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
const targetSkillPath = path3.join(targetDir, code);
|
|
2586
|
+
if (!force && await this.exists(targetSkillPath)) {
|
|
2587
|
+
const message = `\u6280\u80FD ${code} \u5DF2\u5B58\u5728\u4E8E\u76EE\u6807\u76EE\u5F55`;
|
|
2588
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
2589
|
+
return { success: false, message };
|
|
2590
|
+
}
|
|
2591
|
+
work = path3.join(this.tmpDir, `slp-manual-${randomUUID()}`);
|
|
2592
|
+
await fs3.mkdir(work, { recursive: true });
|
|
415
2593
|
const zipPath = path3.join(work, "pkg.zip");
|
|
2594
|
+
const downloadStartedAt = Date.now();
|
|
2595
|
+
emit("download.request.start", { url });
|
|
416
2596
|
const res = await this.fetchImpl(url);
|
|
2597
|
+
emit("download.headers.received", {
|
|
2598
|
+
status: res.status,
|
|
2599
|
+
contentLength: res.headers?.get("content-length") || void 0,
|
|
2600
|
+
contentType: res.headers?.get("content-type") || void 0,
|
|
2601
|
+
elapsedMs: Date.now() - downloadStartedAt
|
|
2602
|
+
});
|
|
417
2603
|
if (!res.ok) {
|
|
418
|
-
|
|
2604
|
+
const message = `\u4E0B\u8F7D\u5931\u8D25: HTTP ${res.status}`;
|
|
2605
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
2606
|
+
return { success: false, message };
|
|
419
2607
|
}
|
|
420
2608
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
2609
|
+
emit("download.body.completed", {
|
|
2610
|
+
bytes: buf.byteLength,
|
|
2611
|
+
elapsedMs: Date.now() - downloadStartedAt
|
|
2612
|
+
});
|
|
421
2613
|
await fs3.writeFile(zipPath, buf);
|
|
2614
|
+
emit("download.file.written", { bytes: buf.byteLength });
|
|
422
2615
|
const staging = path3.join(work, "staging");
|
|
2616
|
+
const unzipStartedAt = Date.now();
|
|
2617
|
+
emit("unzip.start", { extractor: "adm-zip" });
|
|
423
2618
|
await this.unzip(zipPath, staging);
|
|
2619
|
+
emit("unzip.completed", { elapsedMs: Date.now() - unzipStartedAt });
|
|
424
2620
|
const srcRoot = await this.locateSkillRoot(staging, 0);
|
|
425
2621
|
if (!srcRoot) {
|
|
426
|
-
|
|
2622
|
+
const message = `\u4E0B\u8F7D\u5305\u5185\u672A\u627E\u5230 SKILL.md\uFF0C\u975E\u6CD5\u7684\u6280\u80FD\u5305\u7ED3\u6784`;
|
|
2623
|
+
emit("install.failed", { stage: currentStage, message, elapsedMs: Date.now() - startedAt });
|
|
2624
|
+
return { success: false, message };
|
|
427
2625
|
}
|
|
2626
|
+
emit("skill_root.located");
|
|
428
2627
|
const metaPath = path3.join(srcRoot, ".meta.json");
|
|
429
2628
|
if (!await this.exists(metaPath)) {
|
|
430
2629
|
let parsedVersion = version || "unknown";
|
|
@@ -442,13 +2641,37 @@ var SkillUpdater = class {
|
|
|
442
2641
|
publishedAt: Date.now()
|
|
443
2642
|
}, null, 2));
|
|
444
2643
|
}
|
|
445
|
-
|
|
2644
|
+
const targets = [targetDir, ...additionalTargetDirs];
|
|
2645
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
2646
|
+
const rootDir = targets[index];
|
|
2647
|
+
const targetPath = path3.join(rootDir, code);
|
|
2648
|
+
const replaceStartedAt = Date.now();
|
|
2649
|
+
emit("target.replace.start", { targetDir: rootDir, targetIndex: index, targetCount: targets.length });
|
|
2650
|
+
await this.replaceDir(srcRoot, targetPath);
|
|
2651
|
+
emit("target.replace.completed", {
|
|
2652
|
+
targetDir: rootDir,
|
|
2653
|
+
targetIndex: index,
|
|
2654
|
+
targetCount: targets.length,
|
|
2655
|
+
elapsedMs: Date.now() - replaceStartedAt
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
emit("install.completed", { elapsedMs: Date.now() - startedAt, targetCount: targets.length });
|
|
446
2659
|
return { success: true, message: `\u6280\u80FD ${code} \u5B89\u88C5/\u66F4\u65B0\u6210\u529F` };
|
|
447
2660
|
} catch (err) {
|
|
2661
|
+
emit("install.failed", {
|
|
2662
|
+
stage: currentStage,
|
|
2663
|
+
errorName: err?.name,
|
|
2664
|
+
message: err?.message || String(err),
|
|
2665
|
+
stack: err?.stack,
|
|
2666
|
+
elapsedMs: Date.now() - startedAt
|
|
2667
|
+
});
|
|
448
2668
|
return { success: false, message: `\u6267\u884C\u51FA\u9519: ${err.message}` };
|
|
449
2669
|
} finally {
|
|
450
|
-
|
|
451
|
-
|
|
2670
|
+
if (work) {
|
|
2671
|
+
await fs3.rm(work, { recursive: true, force: true }).catch(() => {
|
|
2672
|
+
});
|
|
2673
|
+
emit("cleanup.completed", { elapsedMs: Date.now() - startedAt });
|
|
2674
|
+
}
|
|
452
2675
|
}
|
|
453
2676
|
}
|
|
454
2677
|
};
|
|
@@ -822,6 +3045,9 @@ function parseCore(v) {
|
|
|
822
3045
|
}
|
|
823
3046
|
return nums.length > 0 ? nums : null;
|
|
824
3047
|
}
|
|
3048
|
+
function isComparableVersion(v) {
|
|
3049
|
+
return parseCore(v) !== null;
|
|
3050
|
+
}
|
|
825
3051
|
function compareVersions(a, b) {
|
|
826
3052
|
const na = parseCore(a);
|
|
827
3053
|
const nb = parseCore(b);
|
|
@@ -1275,18 +3501,18 @@ var ConfigSync = class {
|
|
|
1275
3501
|
};
|
|
1276
3502
|
|
|
1277
3503
|
// src/reporter.ts
|
|
1278
|
-
import
|
|
1279
|
-
import
|
|
3504
|
+
import fs6 from "node:fs/promises";
|
|
3505
|
+
import path7 from "node:path";
|
|
1280
3506
|
|
|
1281
3507
|
// src/identity.ts
|
|
1282
3508
|
import os3 from "node:os";
|
|
1283
|
-
import
|
|
1284
|
-
import
|
|
1285
|
-
var execFileAsync2 = promisify2(execFile2);
|
|
3509
|
+
import fs5 from "node:fs/promises";
|
|
3510
|
+
import path6 from "node:path";
|
|
1286
3511
|
async function getGitConfigValue(key) {
|
|
1287
3512
|
try {
|
|
1288
|
-
const
|
|
1289
|
-
|
|
3513
|
+
const gitConfigPath = path6.join(os3.homedir(), ".gitconfig");
|
|
3514
|
+
const content = await fs5.readFile(gitConfigPath, "utf-8");
|
|
3515
|
+
return parseGitConfigValue(content, key);
|
|
1290
3516
|
} catch {
|
|
1291
3517
|
console.warn(
|
|
1292
3518
|
`[skill-logger-plugin] git config --global ${key} \u672A\u8BBE\u7F6E\u3002\u53EF\u6267\u884C\uFF1Agit config --global ${key} '<value>'`
|
|
@@ -1294,6 +3520,26 @@ async function getGitConfigValue(key) {
|
|
|
1294
3520
|
return "";
|
|
1295
3521
|
}
|
|
1296
3522
|
}
|
|
3523
|
+
function parseGitConfigValue(content, key) {
|
|
3524
|
+
const [section, name] = key.split(".");
|
|
3525
|
+
if (!section || !name) return "";
|
|
3526
|
+
let inTargetSection = false;
|
|
3527
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
3528
|
+
const line = rawLine.trim();
|
|
3529
|
+
if (!line || line.startsWith("#") || line.startsWith(";")) continue;
|
|
3530
|
+
const sectionMatch = /^\[([^\]]+)\]$/.exec(line);
|
|
3531
|
+
if (sectionMatch) {
|
|
3532
|
+
inTargetSection = sectionMatch[1].trim() === section;
|
|
3533
|
+
continue;
|
|
3534
|
+
}
|
|
3535
|
+
if (!inTargetSection) continue;
|
|
3536
|
+
const kv = /^([A-Za-z0-9_.-]+)\s*=\s*(.*)$/.exec(line);
|
|
3537
|
+
if (kv?.[1] === name) {
|
|
3538
|
+
return kv[2].trim().replace(/^"|"$/g, "");
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
return "";
|
|
3542
|
+
}
|
|
1297
3543
|
var GitIdentityProvider = class {
|
|
1298
3544
|
cached;
|
|
1299
3545
|
async getIdentity() {
|
|
@@ -1345,9 +3591,9 @@ var Reporter = class {
|
|
|
1345
3591
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
1346
3592
|
const logLine = `[${ts}] [${level}] [skill-logger-plugin] ${msg}
|
|
1347
3593
|
`;
|
|
1348
|
-
const logDir =
|
|
1349
|
-
await
|
|
1350
|
-
await
|
|
3594
|
+
const logDir = path7.dirname(this.paths.eventsLogPath);
|
|
3595
|
+
await fs6.mkdir(logDir, { recursive: true });
|
|
3596
|
+
await fs6.appendFile(path7.join(logDir, "skill-logger.err.log"), logLine);
|
|
1351
3597
|
if (level === "INFO" && this.isDebug) {
|
|
1352
3598
|
console.log("[skill-logger-plugin/reporter]", ...args);
|
|
1353
3599
|
} else if (level === "WARN" || level === "ERROR") {
|
|
@@ -1380,8 +3626,8 @@ var Reporter = class {
|
|
|
1380
3626
|
} catch {
|
|
1381
3627
|
return;
|
|
1382
3628
|
}
|
|
1383
|
-
await
|
|
1384
|
-
await
|
|
3629
|
+
await fs6.mkdir(path7.dirname(this.paths.eventsLogPath), { recursive: true });
|
|
3630
|
+
await fs6.appendFile(this.paths.eventsLogPath, line + "\n");
|
|
1385
3631
|
} catch (err) {
|
|
1386
3632
|
void this.writeFallbackLog("ERROR", "\u5199\u4E8B\u4EF6\u65E5\u5FD7\u5931\u8D25", this.paths.eventsLogPath, err);
|
|
1387
3633
|
}
|
|
@@ -1451,19 +3697,19 @@ var Reporter = class {
|
|
|
1451
3697
|
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
3698
|
return;
|
|
1453
3699
|
}
|
|
1454
|
-
const logDir =
|
|
3700
|
+
const logDir = path7.dirname(this.paths.eventsLogPath);
|
|
1455
3701
|
try {
|
|
1456
|
-
await
|
|
3702
|
+
await fs6.access(this.paths.eventsLogPath);
|
|
1457
3703
|
const timestamp = Date.now();
|
|
1458
|
-
const rotatedPath =
|
|
1459
|
-
await
|
|
1460
|
-
this.debug(`Rotated active log to ${
|
|
3704
|
+
const rotatedPath = path7.join(logDir, `events.${timestamp}.jsonl`);
|
|
3705
|
+
await fs6.rename(this.paths.eventsLogPath, rotatedPath);
|
|
3706
|
+
this.debug(`Rotated active log to ${path7.basename(rotatedPath)}`);
|
|
1461
3707
|
} catch {
|
|
1462
3708
|
}
|
|
1463
3709
|
let files = [];
|
|
1464
3710
|
try {
|
|
1465
|
-
const dirEntries = await
|
|
1466
|
-
files = dirEntries.filter((f) => f.startsWith("events.") && f.endsWith(".jsonl") && f !== "events.jsonl").map((f) =>
|
|
3711
|
+
const dirEntries = await fs6.readdir(logDir);
|
|
3712
|
+
files = dirEntries.filter((f) => f.startsWith("events.") && f.endsWith(".jsonl") && f !== "events.jsonl").map((f) => path7.join(logDir, f));
|
|
1467
3713
|
} catch {
|
|
1468
3714
|
return;
|
|
1469
3715
|
}
|
|
@@ -1476,10 +3722,10 @@ var Reporter = class {
|
|
|
1476
3722
|
const url = config.reportBaseUrl.replace(/\/$/, "") + "/skill_report/batch";
|
|
1477
3723
|
for (const filePath of files) {
|
|
1478
3724
|
try {
|
|
1479
|
-
const content = await
|
|
3725
|
+
const content = await fs6.readFile(filePath, "utf-8");
|
|
1480
3726
|
const lines = this.linesOf(content);
|
|
1481
3727
|
if (lines.length === 0) {
|
|
1482
|
-
await
|
|
3728
|
+
await fs6.unlink(filePath);
|
|
1483
3729
|
continue;
|
|
1484
3730
|
}
|
|
1485
3731
|
let cursor = 0;
|
|
@@ -1508,8 +3754,8 @@ var Reporter = class {
|
|
|
1508
3754
|
if (config.authToken) headers.Authorization = config.authToken;
|
|
1509
3755
|
const res = await this.fetchImpl(url, { method: "POST", headers, body });
|
|
1510
3756
|
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 ${
|
|
3757
|
+
const errBody = await res.text?.().catch(() => "\u65E0\u6CD5\u8BFB\u53D6\u54CD\u5E94\u4F53") ?? "\u65E0\u6CD5\u8BFB\u53D6\u54CD\u5E94\u4F53";
|
|
3758
|
+
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
3759
|
if (res.status === 400 || res.status === 413 || res.status === 422) {
|
|
1514
3760
|
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
3761
|
cursor += slice.length;
|
|
@@ -1518,17 +3764,17 @@ var Reporter = class {
|
|
|
1518
3764
|
allSuccess = false;
|
|
1519
3765
|
break;
|
|
1520
3766
|
}
|
|
1521
|
-
this.debug(`Successfully reported batch of ${events.length} events from ${
|
|
3767
|
+
this.debug(`Successfully reported batch of ${events.length} events from ${path7.basename(filePath)}`);
|
|
1522
3768
|
cursor += slice.length;
|
|
1523
3769
|
}
|
|
1524
3770
|
if (allSuccess) {
|
|
1525
|
-
await
|
|
1526
|
-
this.debug(`Deleted fully processed file: ${
|
|
3771
|
+
await fs6.unlink(filePath);
|
|
3772
|
+
this.debug(`Deleted fully processed file: ${path7.basename(filePath)}`);
|
|
1527
3773
|
} else {
|
|
1528
|
-
this.debug(`File ${
|
|
3774
|
+
this.debug(`File ${path7.basename(filePath)} partially failed. Keeping it for next flush.`);
|
|
1529
3775
|
}
|
|
1530
3776
|
} catch (err) {
|
|
1531
|
-
await this.writeFallbackLog("ERROR", `\u5904\u7406\u6587\u4EF6 ${
|
|
3777
|
+
await this.writeFallbackLog("ERROR", `\u5904\u7406\u6587\u4EF6 ${path7.basename(filePath)} \u5F02\u5E38:`, err);
|
|
1532
3778
|
}
|
|
1533
3779
|
}
|
|
1534
3780
|
} catch (err) {
|
|
@@ -1539,29 +3785,303 @@ var Reporter = class {
|
|
|
1539
3785
|
}
|
|
1540
3786
|
};
|
|
1541
3787
|
|
|
3788
|
+
// src/expert-skill-layout.ts
|
|
3789
|
+
import fs7 from "node:fs/promises";
|
|
3790
|
+
import path8 from "node:path";
|
|
3791
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3792
|
+
var ASSISTANT_WORKSPACE_RE = /^workspace-assistant-\d{5,}$/;
|
|
3793
|
+
var REPAIR_RESIDUE_RE = /^\.(.+)\.repair-(old|new)-(.+)$/;
|
|
3794
|
+
async function lstatOrUndefined(filePath) {
|
|
3795
|
+
try {
|
|
3796
|
+
return await fs7.lstat(filePath);
|
|
3797
|
+
} catch (error) {
|
|
3798
|
+
if (error?.code === "ENOENT") return void 0;
|
|
3799
|
+
throw error;
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
async function isRegularFile(filePath) {
|
|
3803
|
+
const stat = await lstatOrUndefined(filePath);
|
|
3804
|
+
return Boolean(stat?.isFile() && !stat.isSymbolicLink());
|
|
3805
|
+
}
|
|
3806
|
+
async function removeRealDirectory(dirPath) {
|
|
3807
|
+
const stat = await lstatOrUndefined(dirPath);
|
|
3808
|
+
if (!stat) return;
|
|
3809
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
3810
|
+
throw new Error(`\u62D2\u7EDD\u6E05\u7406\u975E\u771F\u5B9E\u76EE\u5F55: ${dirPath}`);
|
|
3811
|
+
}
|
|
3812
|
+
await fs7.rm(dirPath, { recursive: true });
|
|
3813
|
+
}
|
|
3814
|
+
async function removeNestedDirectoryIfPresent(dirPath) {
|
|
3815
|
+
const stat = await lstatOrUndefined(dirPath);
|
|
3816
|
+
if (!stat) return;
|
|
3817
|
+
if (stat.isSymbolicLink()) throw new Error(`\u62D2\u7EDD\u6E05\u7406\u7B26\u53F7\u94FE\u63A5: ${dirPath}`);
|
|
3818
|
+
if (stat.isDirectory()) await fs7.rm(dirPath, { recursive: true });
|
|
3819
|
+
}
|
|
3820
|
+
async function recoverRepairResidues(skillsRoot, entries, result) {
|
|
3821
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3822
|
+
for (const entry of entries) {
|
|
3823
|
+
const match2 = REPAIR_RESIDUE_RE.exec(entry.name);
|
|
3824
|
+
if (!match2) continue;
|
|
3825
|
+
const group = groups.get(match2[1]) ?? { old: [], stage: [] };
|
|
3826
|
+
group[match2[2] === "old" ? "old" : "stage"].push(path8.join(skillsRoot, entry.name));
|
|
3827
|
+
groups.set(match2[1], group);
|
|
3828
|
+
}
|
|
3829
|
+
for (const [code, group] of groups) {
|
|
3830
|
+
const targetDir = path8.join(skillsRoot, code);
|
|
3831
|
+
try {
|
|
3832
|
+
const targetStat = await lstatOrUndefined(targetDir);
|
|
3833
|
+
if (targetStat?.isSymbolicLink() || targetStat && !targetStat.isDirectory()) {
|
|
3834
|
+
throw new Error(`\u89C4\u8303\u8DEF\u5F84\u4E0D\u662F\u53EF\u5B89\u5168\u64CD\u4F5C\u7684\u771F\u5B9E\u76EE\u5F55: ${targetDir}`);
|
|
3835
|
+
}
|
|
3836
|
+
group.old.sort().reverse();
|
|
3837
|
+
if (!targetStat && group.old.length > 0) {
|
|
3838
|
+
const restore = group.old.shift();
|
|
3839
|
+
const restoreStat = await lstatOrUndefined(restore);
|
|
3840
|
+
if (!restoreStat?.isDirectory() || restoreStat.isSymbolicLink()) {
|
|
3841
|
+
throw new Error(`\u62D2\u7EDD\u4ECE\u975E\u771F\u5B9E\u76EE\u5F55\u6062\u590D: ${restore}`);
|
|
3842
|
+
}
|
|
3843
|
+
await fs7.rename(restore, targetDir);
|
|
3844
|
+
}
|
|
3845
|
+
if (await lstatOrUndefined(targetDir)) {
|
|
3846
|
+
for (const residue of [...group.old, ...group.stage]) {
|
|
3847
|
+
await removeRealDirectory(residue);
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
} catch (error) {
|
|
3851
|
+
result.errors.push({ path: targetDir, message: error?.message || String(error) });
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
async function promoteNestedSkill(sourceDir, targetDir) {
|
|
3856
|
+
const parent = path8.dirname(targetDir);
|
|
3857
|
+
const tag = `${Date.now()}-${randomUUID2().slice(0, 8)}`;
|
|
3858
|
+
const stage = path8.join(parent, `.${path8.basename(targetDir)}.repair-new-${tag}`);
|
|
3859
|
+
const old = path8.join(parent, `.${path8.basename(targetDir)}.repair-old-${tag}`);
|
|
3860
|
+
let movedOld = false;
|
|
3861
|
+
try {
|
|
3862
|
+
await fs7.cp(sourceDir, stage, { recursive: true });
|
|
3863
|
+
await removeNestedDirectoryIfPresent(path8.join(stage, path8.basename(targetDir)));
|
|
3864
|
+
await fs7.rename(targetDir, old);
|
|
3865
|
+
movedOld = true;
|
|
3866
|
+
await fs7.rename(stage, targetDir);
|
|
3867
|
+
} catch (error) {
|
|
3868
|
+
const rollbackErrors = [];
|
|
3869
|
+
try {
|
|
3870
|
+
await removeRealDirectory(stage);
|
|
3871
|
+
} catch (cleanupError) {
|
|
3872
|
+
rollbackErrors.push(`\u6E05\u7406\u6682\u5B58\u76EE\u5F55\u5931\u8D25: ${cleanupError?.message || String(cleanupError)}`);
|
|
3873
|
+
}
|
|
3874
|
+
if (movedOld) {
|
|
3875
|
+
try {
|
|
3876
|
+
await fs7.rename(old, targetDir);
|
|
3877
|
+
} catch (restoreError) {
|
|
3878
|
+
rollbackErrors.push(`\u6062\u590D\u65E7\u76EE\u5F55\u5931\u8D25: ${restoreError?.message || String(restoreError)}`);
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
if (rollbackErrors.length > 0) {
|
|
3882
|
+
throw new Error(`${error?.message || String(error)}; ${rollbackErrors.join("; ")}`);
|
|
3883
|
+
}
|
|
3884
|
+
throw error;
|
|
3885
|
+
}
|
|
3886
|
+
await removeRealDirectory(old);
|
|
3887
|
+
}
|
|
3888
|
+
async function repairNestedExpertSkillLayouts(openclawRoot) {
|
|
3889
|
+
const result = {
|
|
3890
|
+
scannedWorkspaces: 0,
|
|
3891
|
+
repaired: [],
|
|
3892
|
+
skipped: [],
|
|
3893
|
+
errors: []
|
|
3894
|
+
};
|
|
3895
|
+
let workspaceEntries;
|
|
3896
|
+
try {
|
|
3897
|
+
workspaceEntries = await fs7.readdir(openclawRoot, { withFileTypes: true });
|
|
3898
|
+
} catch (error) {
|
|
3899
|
+
result.errors.push({ path: openclawRoot, message: error?.message || String(error) });
|
|
3900
|
+
return result;
|
|
3901
|
+
}
|
|
3902
|
+
for (const workspaceEntry of workspaceEntries) {
|
|
3903
|
+
if (!workspaceEntry.isDirectory() || !ASSISTANT_WORKSPACE_RE.test(workspaceEntry.name)) continue;
|
|
3904
|
+
result.scannedWorkspaces += 1;
|
|
3905
|
+
const skillsRoot = path8.join(openclawRoot, workspaceEntry.name, ".user", "skills");
|
|
3906
|
+
let skillEntries;
|
|
3907
|
+
try {
|
|
3908
|
+
skillEntries = await fs7.readdir(skillsRoot, { withFileTypes: true });
|
|
3909
|
+
await recoverRepairResidues(skillsRoot, skillEntries, result);
|
|
3910
|
+
skillEntries = await fs7.readdir(skillsRoot, { withFileTypes: true });
|
|
3911
|
+
} catch (error) {
|
|
3912
|
+
if (error?.code !== "ENOENT") {
|
|
3913
|
+
result.errors.push({ path: skillsRoot, message: error?.message || String(error) });
|
|
3914
|
+
}
|
|
3915
|
+
continue;
|
|
3916
|
+
}
|
|
3917
|
+
for (const skillEntry of skillEntries) {
|
|
3918
|
+
if (!skillEntry.isDirectory() || skillEntry.name.startsWith(".")) continue;
|
|
3919
|
+
const outerDir = path8.join(skillsRoot, skillEntry.name);
|
|
3920
|
+
try {
|
|
3921
|
+
const candidates = [];
|
|
3922
|
+
const outerHasSkill = await isRegularFile(path8.join(outerDir, "SKILL.md"));
|
|
3923
|
+
if (outerHasSkill) {
|
|
3924
|
+
const version = await readSkillVersion(outerDir);
|
|
3925
|
+
if (!version) {
|
|
3926
|
+
result.skipped.push(outerDir);
|
|
3927
|
+
continue;
|
|
3928
|
+
}
|
|
3929
|
+
candidates.push({ dir: outerDir, version });
|
|
3930
|
+
}
|
|
3931
|
+
let cursor = outerDir;
|
|
3932
|
+
let nestedCount = 0;
|
|
3933
|
+
while (true) {
|
|
3934
|
+
const nestedDir = path8.join(cursor, skillEntry.name);
|
|
3935
|
+
const nestedStat = await lstatOrUndefined(nestedDir);
|
|
3936
|
+
if (!nestedStat) break;
|
|
3937
|
+
if (nestedStat.isSymbolicLink()) {
|
|
3938
|
+
throw new Error(`\u62D2\u7EDD\u8DDF\u968F\u540C\u540D\u7B26\u53F7\u94FE\u63A5: ${nestedDir}`);
|
|
3939
|
+
}
|
|
3940
|
+
if (!nestedStat.isDirectory()) break;
|
|
3941
|
+
cursor = nestedDir;
|
|
3942
|
+
const skillMd = path8.join(nestedDir, "SKILL.md");
|
|
3943
|
+
const skillStat = await lstatOrUndefined(skillMd);
|
|
3944
|
+
if (skillStat?.isSymbolicLink()) {
|
|
3945
|
+
throw new Error(`\u62D2\u7EDD\u8BFB\u53D6\u7B26\u53F7\u94FE\u63A5 SKILL.md: ${skillMd}`);
|
|
3946
|
+
}
|
|
3947
|
+
if (!skillStat?.isFile()) continue;
|
|
3948
|
+
nestedCount += 1;
|
|
3949
|
+
const version = await readSkillVersion(nestedDir);
|
|
3950
|
+
if (!version) {
|
|
3951
|
+
result.skipped.push(outerDir);
|
|
3952
|
+
candidates.length = 0;
|
|
3953
|
+
break;
|
|
3954
|
+
}
|
|
3955
|
+
candidates.push({ dir: nestedDir, version });
|
|
3956
|
+
}
|
|
3957
|
+
if (nestedCount === 0 || candidates.length === 0) continue;
|
|
3958
|
+
if (candidates.some((candidate) => !isComparableVersion(candidate.version))) {
|
|
3959
|
+
result.skipped.push(outerDir);
|
|
3960
|
+
continue;
|
|
3961
|
+
}
|
|
3962
|
+
let source = candidates[0];
|
|
3963
|
+
for (const candidate of candidates.slice(1)) {
|
|
3964
|
+
if (compareVersions(candidate.version, source.version) >= 0) source = candidate;
|
|
3965
|
+
}
|
|
3966
|
+
if (source.dir === outerDir) {
|
|
3967
|
+
result.skipped.push(outerDir);
|
|
3968
|
+
continue;
|
|
3969
|
+
}
|
|
3970
|
+
await promoteNestedSkill(source.dir, outerDir);
|
|
3971
|
+
result.repaired.push(outerDir);
|
|
3972
|
+
} catch (error) {
|
|
3973
|
+
result.errors.push({ path: outerDir, message: error?.message || String(error) });
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
return result;
|
|
3978
|
+
}
|
|
3979
|
+
|
|
1542
3980
|
// src/ws-client.ts
|
|
1543
3981
|
import WebSocket from "ws";
|
|
1544
|
-
import
|
|
1545
|
-
import
|
|
3982
|
+
import path9 from "path";
|
|
3983
|
+
import fs8 from "fs/promises";
|
|
3984
|
+
import { DatabaseSync } from "node:sqlite";
|
|
1546
3985
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
1547
3986
|
var HEARTBEAT_ACK_TIMEOUT_MS = 75e3;
|
|
1548
3987
|
var AGENT_SCAN_INTERVAL_MS = 3 * 60 * 1e3;
|
|
1549
|
-
var ASSISTANT_WORKSPACE_PREFIX = "workspace-assistant-";
|
|
1550
3988
|
var ASSISTANT_AGENT_PREFIX = "assistant-";
|
|
1551
3989
|
var ASSISTANT_WORKSPACE_ID_RE = /^\d{5,}$/;
|
|
1552
|
-
function
|
|
1553
|
-
if (!
|
|
1554
|
-
const
|
|
1555
|
-
if (!
|
|
1556
|
-
|
|
3990
|
+
function enabledAgentIdsFromAccounts(config) {
|
|
3991
|
+
if (!config || typeof config !== "object") return [];
|
|
3992
|
+
const channels = config.channels;
|
|
3993
|
+
if (!channels || typeof channels !== "object") return [];
|
|
3994
|
+
const cworkConfig = channels.xg_cwork_im;
|
|
3995
|
+
if (!cworkConfig || typeof cworkConfig !== "object") return [];
|
|
3996
|
+
const accounts = cworkConfig.accounts;
|
|
3997
|
+
if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) return [];
|
|
3998
|
+
const agentIds = /* @__PURE__ */ new Set();
|
|
3999
|
+
for (const account of Object.values(accounts)) {
|
|
4000
|
+
if (!account || typeof account !== "object" || account.enabled === false) continue;
|
|
4001
|
+
if (typeof account.agentId !== "string") continue;
|
|
4002
|
+
const agentId = account.agentId.trim();
|
|
4003
|
+
if (agentId) agentIds.add(agentId);
|
|
4004
|
+
}
|
|
4005
|
+
return [...agentIds];
|
|
4006
|
+
}
|
|
4007
|
+
function resolveSkillInstallTarget(config, userId) {
|
|
4008
|
+
if (!config || typeof config !== "object") throw new Error("openclaw.json \u914D\u7F6E\u65E0\u6548");
|
|
4009
|
+
const root = config;
|
|
4010
|
+
const accounts = root.channels?.xg_cwork_im?.accounts;
|
|
4011
|
+
if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) {
|
|
4012
|
+
throw new Error(`\u672A\u627E\u5230 userId=${userId} \u7684 xg_cwork_im account`);
|
|
4013
|
+
}
|
|
4014
|
+
const matched = Object.entries(accounts).filter(([, account2]) => account2 && typeof account2 === "object" && account2.agentId === userId);
|
|
4015
|
+
if (matched.length !== 1) {
|
|
4016
|
+
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`);
|
|
4017
|
+
}
|
|
4018
|
+
const [accountId, account] = matched[0];
|
|
4019
|
+
if (account.enabled === false) throw new Error(`userId=${userId} \u5BF9\u5E94 Agent \u5DF2\u7981\u7528`);
|
|
4020
|
+
const bindingAccountIds = /* @__PURE__ */ new Set([accountId, userId]);
|
|
4021
|
+
const bindings = Array.isArray(root.bindings) ? root.bindings : [];
|
|
4022
|
+
const binding = bindings.find((item) => {
|
|
4023
|
+
if (!item || typeof item !== "object") return false;
|
|
4024
|
+
const candidate = item;
|
|
4025
|
+
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;
|
|
4026
|
+
});
|
|
4027
|
+
const localAgentId = typeof binding?.agentId === "string" ? binding.agentId : userId;
|
|
4028
|
+
const list = Array.isArray(root.agents?.list) ? root.agents.list : [];
|
|
4029
|
+
const agent = list.find(
|
|
4030
|
+
(item) => Boolean(item) && typeof item === "object" && item.id === localAgentId
|
|
4031
|
+
);
|
|
4032
|
+
if (!agent) throw new Error(`\u672A\u627E\u5230\u672C\u5730 Agent \u914D\u7F6E: ${localAgentId}`);
|
|
4033
|
+
const workspace = typeof agent.workspace === "string" ? agent.workspace : root.agents?.defaults?.workspace;
|
|
4034
|
+
if (typeof workspace !== "string" || !workspace.trim()) {
|
|
4035
|
+
throw new Error(`\u672C\u5730 Agent ${localAgentId} \u672A\u914D\u7F6E workspace`);
|
|
4036
|
+
}
|
|
4037
|
+
return { skillsDir: path9.join(workspace, "skills"), localAgentId };
|
|
1557
4038
|
}
|
|
1558
4039
|
function normalizeAssistantUserId(userId) {
|
|
1559
|
-
const safeUserId =
|
|
4040
|
+
const safeUserId = path9.basename(userId);
|
|
1560
4041
|
if (safeUserId !== userId) return void 0;
|
|
1561
4042
|
const pureId = safeUserId.startsWith(ASSISTANT_AGENT_PREFIX) ? safeUserId.slice(ASSISTANT_AGENT_PREFIX.length) : safeUserId;
|
|
1562
4043
|
if (!ASSISTANT_WORKSPACE_ID_RE.test(pureId)) return void 0;
|
|
1563
4044
|
return pureId;
|
|
1564
4045
|
}
|
|
4046
|
+
function normalizeCommandCode(code) {
|
|
4047
|
+
if (typeof code !== "string" || code.length === 0 || code === "." || code === "..") return void 0;
|
|
4048
|
+
if (code.includes("/") || code.includes("\\") || code.includes("\0")) return void 0;
|
|
4049
|
+
if (path9.basename(code) !== code) return void 0;
|
|
4050
|
+
return code;
|
|
4051
|
+
}
|
|
4052
|
+
function shouldSyncBuiltInTemplate(action, isBuiltIn) {
|
|
4053
|
+
return action === "UPDATE_SKILL" && isBuiltIn === true;
|
|
4054
|
+
}
|
|
4055
|
+
function resolveGatewaySkillTarget(home = openclawHome()) {
|
|
4056
|
+
return path9.join(home, "skills");
|
|
4057
|
+
}
|
|
4058
|
+
function isGatewaySkillCommand(action, installScope) {
|
|
4059
|
+
return installScope === "gateway" && ["INSTALL_SKILL", "UPDATE_SKILL", "UNINSTALL_SKILL"].includes(String(action || ""));
|
|
4060
|
+
}
|
|
4061
|
+
async function findInstalledExpertSkillsRoot(rootPath, pureId, code) {
|
|
4062
|
+
const skillsRoot = path9.join(rootPath, `workspace-assistant-${pureId}`, ".user", "skills");
|
|
4063
|
+
try {
|
|
4064
|
+
const stat = await fs8.stat(path9.join(skillsRoot, code));
|
|
4065
|
+
return stat.isDirectory() ? skillsRoot : void 0;
|
|
4066
|
+
} catch {
|
|
4067
|
+
return void 0;
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
function defaultOpenclawSqlitePath() {
|
|
4071
|
+
return path9.join(openclawHome(), "state", "openclaw.sqlite");
|
|
4072
|
+
}
|
|
4073
|
+
function readCronJobsByAgentId(agentId, sqlitePath = defaultOpenclawSqlitePath(), onError) {
|
|
4074
|
+
let db;
|
|
4075
|
+
try {
|
|
4076
|
+
db = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
4077
|
+
return db.prepare("SELECT * FROM cron_jobs WHERE agent_id = ?").all(agentId);
|
|
4078
|
+
} catch (err) {
|
|
4079
|
+
onError?.(err);
|
|
4080
|
+
return [];
|
|
4081
|
+
} finally {
|
|
4082
|
+
db?.close();
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
1565
4085
|
var GatewayWsClient = class {
|
|
1566
4086
|
ws = null;
|
|
1567
4087
|
options;
|
|
@@ -1588,16 +4108,35 @@ var GatewayWsClient = class {
|
|
|
1588
4108
|
}
|
|
1589
4109
|
}
|
|
1590
4110
|
logLine += "\n";
|
|
1591
|
-
const logsDir =
|
|
1592
|
-
|
|
1593
|
-
const logPath =
|
|
1594
|
-
|
|
4111
|
+
const logsDir = path9.join(openclawHome(), "logs");
|
|
4112
|
+
fs8.mkdir(logsDir, { recursive: true }).then(() => {
|
|
4113
|
+
const logPath = path9.join(logsDir, "skill-logger.err");
|
|
4114
|
+
fs8.appendFile(logPath, logLine).catch(() => {
|
|
1595
4115
|
});
|
|
1596
4116
|
}).catch(() => {
|
|
1597
4117
|
});
|
|
1598
4118
|
} catch (e) {
|
|
1599
4119
|
}
|
|
1600
4120
|
}
|
|
4121
|
+
createInstallTrace(context) {
|
|
4122
|
+
return (stage, data) => {
|
|
4123
|
+
this.appendLogToFile(stage === "install.failed" ? "ERROR" : "INFO", "Install", stage, {
|
|
4124
|
+
...context,
|
|
4125
|
+
...data
|
|
4126
|
+
});
|
|
4127
|
+
};
|
|
4128
|
+
}
|
|
4129
|
+
/** 普通 Skill 的所有读写操作共用这一个配置驱动的寻址入口。 */
|
|
4130
|
+
async resolveRegularSkillTarget(userId) {
|
|
4131
|
+
const configPath = path9.join(openclawHome(), "openclaw.json");
|
|
4132
|
+
let config;
|
|
4133
|
+
try {
|
|
4134
|
+
config = JSON.parse(await fs8.readFile(configPath, "utf-8"));
|
|
4135
|
+
} catch (err) {
|
|
4136
|
+
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6 openclaw.json: ${err?.message || String(err)}`);
|
|
4137
|
+
}
|
|
4138
|
+
return resolveSkillInstallTarget(config, userId).skillsDir;
|
|
4139
|
+
}
|
|
1601
4140
|
constructor(options) {
|
|
1602
4141
|
this.options = options;
|
|
1603
4142
|
}
|
|
@@ -1693,26 +4232,26 @@ var GatewayWsClient = class {
|
|
|
1693
4232
|
}
|
|
1694
4233
|
});
|
|
1695
4234
|
}
|
|
1696
|
-
/**
|
|
1697
|
-
* 扫描 OpenClaw 根目录下的 workspace-assistant-{userId} 目录。
|
|
1698
|
-
* userId 必须是至少 5 位数字。
|
|
1699
|
-
*/
|
|
4235
|
+
/** 从 openclaw.json 的 xg_cwork_im accounts 读取当前启用的 agent。 */
|
|
1700
4236
|
async scanAndReportAgents(isInitialReport) {
|
|
1701
4237
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
|
1702
4238
|
try {
|
|
1703
|
-
const
|
|
1704
|
-
let
|
|
4239
|
+
const configPath = path9.join(openclawHome(), "openclaw.json");
|
|
4240
|
+
let rawConfig;
|
|
1705
4241
|
try {
|
|
1706
|
-
|
|
4242
|
+
rawConfig = await fs8.readFile(configPath, "utf-8");
|
|
1707
4243
|
} catch (e) {
|
|
1708
|
-
this.appendLogToFile("WARN", "AgentScan", "OpenClaw
|
|
4244
|
+
this.appendLogToFile("WARN", "AgentScan", "OpenClaw config is not readable; skipping this scan cycle", e);
|
|
1709
4245
|
return;
|
|
1710
4246
|
}
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
4247
|
+
let config;
|
|
4248
|
+
try {
|
|
4249
|
+
config = JSON.parse(rawConfig);
|
|
4250
|
+
} catch (e) {
|
|
4251
|
+
this.appendLogToFile("WARN", "AgentScan", "OpenClaw config is invalid JSON; skipping this scan cycle", e);
|
|
4252
|
+
return;
|
|
1715
4253
|
}
|
|
4254
|
+
const newAgentIds = new Set(enabledAgentIdsFromAccounts(config));
|
|
1716
4255
|
let changed = false;
|
|
1717
4256
|
if (newAgentIds.size !== this.currentAgentIds.size) {
|
|
1718
4257
|
changed = true;
|
|
@@ -1820,7 +4359,8 @@ var GatewayWsClient = class {
|
|
|
1820
4359
|
gatewayId: this.options.gatewayId,
|
|
1821
4360
|
agentIds: Array.from(this.currentAgentIds),
|
|
1822
4361
|
clientTime: Date.now(),
|
|
1823
|
-
supportsBatch: true
|
|
4362
|
+
supportsBatch: true,
|
|
4363
|
+
supportsGatewaySkillScope: true
|
|
1824
4364
|
}, "Heartbeat");
|
|
1825
4365
|
}
|
|
1826
4366
|
sendClientHeartbeat() {
|
|
@@ -1849,22 +4389,57 @@ var GatewayWsClient = class {
|
|
|
1849
4389
|
* 核心指令分发中心:完全跳过沙盒,基于 userId 直接进行底层物理文件操作
|
|
1850
4390
|
*/
|
|
1851
4391
|
async handleMessage(msg) {
|
|
1852
|
-
const { action, userId, code, url, force, version, replyId } = msg;
|
|
1853
|
-
this.appendLogToFile("INFO", "Command", `Received WS message`, {
|
|
1854
|
-
|
|
1855
|
-
|
|
4392
|
+
const { action, userId, code, url, force, version, replyId, isBuiltIn, installScope } = msg;
|
|
4393
|
+
this.appendLogToFile("INFO", "Command", `Received WS message`, {
|
|
4394
|
+
action,
|
|
4395
|
+
userId,
|
|
4396
|
+
code,
|
|
4397
|
+
version,
|
|
4398
|
+
replyId,
|
|
4399
|
+
isBuiltIn,
|
|
4400
|
+
installScope,
|
|
4401
|
+
hasDirectUrl: Boolean(url)
|
|
4402
|
+
});
|
|
4403
|
+
if (!action) {
|
|
4404
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing action`, msg);
|
|
4405
|
+
return;
|
|
4406
|
+
}
|
|
4407
|
+
if (action === "GET_CRON_JOBS_BY_AGENT_ID") {
|
|
4408
|
+
const agentId = typeof msg.agent_id === "string" ? msg.agent_id : typeof msg.agentId === "string" ? msg.agentId : userId;
|
|
4409
|
+
if (!agentId) {
|
|
4410
|
+
this.reply(replyId, { success: false, message: "Missing agent_id parameter", action });
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
4413
|
+
try {
|
|
4414
|
+
const data = readCronJobsByAgentId(agentId, defaultOpenclawSqlitePath(), (err) => {
|
|
4415
|
+
this.appendLogToFile("WARN", "Command", `GET_CRON_JOBS_BY_AGENT_ID sqlite lookup skipped`, err);
|
|
4416
|
+
});
|
|
4417
|
+
this.reply(replyId, { success: true, data, action });
|
|
4418
|
+
} catch (err) {
|
|
4419
|
+
this.appendLogToFile("ERROR", "Command", `GET_CRON_JOBS_BY_AGENT_ID threw`, err);
|
|
4420
|
+
this.reply(replyId, { success: false, message: err.message, action });
|
|
4421
|
+
}
|
|
1856
4422
|
return;
|
|
1857
4423
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
4424
|
+
if (!userId) {
|
|
4425
|
+
this.appendLogToFile("WARN", "Command", `Message dropped: missing userId`, msg);
|
|
4426
|
+
return;
|
|
4427
|
+
}
|
|
4428
|
+
const safeCode = normalizeCommandCode(code);
|
|
4429
|
+
if (code !== void 0 && !safeCode) {
|
|
4430
|
+
this.reply(replyId, { success: false, message: `Invalid code: ${String(code)}`, action });
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4433
|
+
const gatewaySkillCommand = isGatewaySkillCommand(action, installScope);
|
|
4434
|
+
const pureId = gatewaySkillCommand ? void 0 : normalizeAssistantUserId(userId);
|
|
4435
|
+
if (!gatewaySkillCommand && !pureId) {
|
|
1861
4436
|
this.reply(replyId, { success: false, message: `Invalid userId: ${userId}`, action });
|
|
1862
4437
|
return;
|
|
1863
4438
|
}
|
|
1864
|
-
const targetDir = path7.join(openclawHome(), `workspace-assistant-${pureId}`, "skills");
|
|
1865
4439
|
try {
|
|
1866
4440
|
if (action === "INSTALL_SKILL") {
|
|
1867
4441
|
if (!safeCode) throw new Error("Missing code parameter");
|
|
4442
|
+
const targetDir = gatewaySkillCommand ? resolveGatewaySkillTarget() : await this.resolveRegularSkillTarget(userId);
|
|
1868
4443
|
console.log(`[skill-logger-plugin][WS] Executing INSTALL for user ${userId}, code: ${safeCode}`);
|
|
1869
4444
|
this.appendLogToFile("INFO", "Command", `INSTALL_SKILL received`, { userId, code: safeCode, version });
|
|
1870
4445
|
const result = await this.options.updater.manualInstall({
|
|
@@ -1872,109 +4447,163 @@ var GatewayWsClient = class {
|
|
|
1872
4447
|
url,
|
|
1873
4448
|
version,
|
|
1874
4449
|
force: force !== false,
|
|
1875
|
-
targetDir
|
|
4450
|
+
targetDir,
|
|
4451
|
+
trace: this.createInstallTrace({ action, replyId, userId, code: safeCode })
|
|
4452
|
+
});
|
|
4453
|
+
this.reply(replyId, {
|
|
4454
|
+
success: result.success,
|
|
4455
|
+
message: result.message,
|
|
4456
|
+
action,
|
|
4457
|
+
data: { code: safeCode, version, installScope: gatewaySkillCommand ? "gateway" : "agent" }
|
|
1876
4458
|
});
|
|
1877
|
-
this.reply(replyId, { success: result.success, message: result.message, action });
|
|
1878
4459
|
} else if (action === "UNINSTALL_SKILL") {
|
|
1879
4460
|
if (!safeCode) throw new Error("Missing code parameter");
|
|
4461
|
+
const targetDir = gatewaySkillCommand ? resolveGatewaySkillTarget() : await this.resolveRegularSkillTarget(userId);
|
|
1880
4462
|
console.log(`[skill-logger-plugin][WS] Executing UNINSTALL for user ${userId}, code: ${safeCode}`);
|
|
1881
4463
|
this.appendLogToFile("INFO", "Command", `UNINSTALL_SKILL received`, { userId, code: safeCode });
|
|
1882
|
-
const skillPath =
|
|
1883
|
-
await
|
|
1884
|
-
this.reply(replyId, {
|
|
4464
|
+
const skillPath = path9.join(targetDir, safeCode);
|
|
4465
|
+
await fs8.rm(skillPath, { recursive: true, force: true });
|
|
4466
|
+
this.reply(replyId, {
|
|
4467
|
+
success: true,
|
|
4468
|
+
message: `Skill ${safeCode} removed`,
|
|
4469
|
+
action,
|
|
4470
|
+
data: { code: safeCode, installScope: gatewaySkillCommand ? "gateway" : "agent", removed: true }
|
|
4471
|
+
});
|
|
1885
4472
|
} else if (action === "LIST_SKILLS") {
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
if (!targetDirExists) {
|
|
1895
|
-
throw new Error(`Target skills directory does not exist: ${targetDir}`);
|
|
1896
|
-
}
|
|
1897
|
-
const entries = await fs6.readdir(targetDir, { withFileTypes: true });
|
|
1898
|
-
const dirs = entries.filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith("."));
|
|
1899
|
-
for (const e of dirs) {
|
|
1900
|
-
const skillDir = path7.join(targetDir, e.name);
|
|
1901
|
-
const skillMdPath = path7.join(skillDir, "SKILL.md");
|
|
4473
|
+
const regularTargetDir = await this.resolveRegularSkillTarget(userId);
|
|
4474
|
+
const skillsByCode = /* @__PURE__ */ new Map();
|
|
4475
|
+
const sources = [
|
|
4476
|
+
{ dir: regularTargetDir, gatewayBuiltIn: false },
|
|
4477
|
+
{ dir: resolveGatewaySkillTarget(), gatewayBuiltIn: true }
|
|
4478
|
+
];
|
|
4479
|
+
for (const source of sources) {
|
|
4480
|
+
let entries;
|
|
1902
4481
|
try {
|
|
1903
|
-
|
|
1904
|
-
if (!stat.isFile()) continue;
|
|
4482
|
+
entries = await fs8.readdir(source.dir, { withFileTypes: true });
|
|
1905
4483
|
} catch (err) {
|
|
1906
|
-
continue;
|
|
4484
|
+
if (err?.code === "ENOENT") continue;
|
|
4485
|
+
throw err;
|
|
1907
4486
|
}
|
|
1908
|
-
const
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(mdContent)?.[1] ?? "";
|
|
1918
|
-
const parsedName = /(^|\n)name:\s*(.+)/.exec(fm)?.[2]?.trim();
|
|
1919
|
-
if (parsedName) name = parsedName;
|
|
1920
|
-
const descMatch = /(^|\n)description:\s*(?:>\s*\n\s*)?(.*?)(?=\n[a-z]+:|\n---|$)/is.exec(fm);
|
|
1921
|
-
if (descMatch && descMatch[2]) {
|
|
1922
|
-
description = descMatch[2].replace(/\n\s+/g, " ").trim();
|
|
4487
|
+
const dirs = entries.filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith("."));
|
|
4488
|
+
for (const e of dirs) {
|
|
4489
|
+
const skillDir = path9.join(source.dir, e.name);
|
|
4490
|
+
const skillMdPath = path9.join(skillDir, "SKILL.md");
|
|
4491
|
+
try {
|
|
4492
|
+
const stat = await fs8.stat(skillMdPath);
|
|
4493
|
+
if (!stat.isFile()) continue;
|
|
4494
|
+
} catch {
|
|
4495
|
+
continue;
|
|
1923
4496
|
}
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
4497
|
+
const metaPath = path9.join(skillDir, ".meta.json");
|
|
4498
|
+
let isPlatform = source.gatewayBuiltIn;
|
|
4499
|
+
let isBuiltIn2 = source.gatewayBuiltIn || e.isSymbolicLink();
|
|
4500
|
+
let metaData = null;
|
|
4501
|
+
let name = e.name;
|
|
4502
|
+
let description = "";
|
|
4503
|
+
let skillVersion = "";
|
|
4504
|
+
try {
|
|
4505
|
+
const mdContent = await fs8.readFile(skillMdPath, "utf8");
|
|
4506
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(mdContent)?.[1] ?? "";
|
|
4507
|
+
const parsedName = /(^|\n)name:\s*(.+)/.exec(fm)?.[2]?.trim();
|
|
4508
|
+
if (parsedName) name = parsedName;
|
|
4509
|
+
const descMatch = /(^|\n)description:\s*(?:>\s*\n\s*)?(.*?)(?=\n[a-z]+:|\n---|$)/is.exec(fm);
|
|
4510
|
+
if (descMatch?.[2]) description = descMatch[2].replace(/\n\s+/g, " ").trim();
|
|
4511
|
+
} catch {
|
|
4512
|
+
}
|
|
4513
|
+
try {
|
|
4514
|
+
const parsed = JSON.parse(await fs8.readFile(metaPath, "utf8"));
|
|
4515
|
+
if (parsed) {
|
|
4516
|
+
if (parsed.ownerId === "CMS" || parsed.ownerId === "CMS_COMPAT") isPlatform = true;
|
|
4517
|
+
if (parsed.isBuiltIn === true || parsed.ownerId === "built-in") isBuiltIn2 = true;
|
|
4518
|
+
metaData = parsed;
|
|
4519
|
+
}
|
|
4520
|
+
} catch {
|
|
4521
|
+
}
|
|
4522
|
+
const resolvedVersion = await readSkillVersion(skillDir);
|
|
4523
|
+
if (resolvedVersion) skillVersion = resolvedVersion;
|
|
4524
|
+
if (isPlatform) {
|
|
4525
|
+
skillsByCode.set(e.name, {
|
|
4526
|
+
code: e.name,
|
|
4527
|
+
isPlatform: true,
|
|
4528
|
+
isBuiltIn: isBuiltIn2,
|
|
4529
|
+
version: skillVersion,
|
|
4530
|
+
name,
|
|
4531
|
+
description,
|
|
4532
|
+
publishedAt: metaData?.publishedAt
|
|
4533
|
+
});
|
|
4534
|
+
} else {
|
|
4535
|
+
skillsByCode.set(e.name, {
|
|
4536
|
+
code: e.name,
|
|
4537
|
+
isPlatform: false,
|
|
4538
|
+
isBuiltIn: isBuiltIn2,
|
|
4539
|
+
version: skillVersion,
|
|
4540
|
+
name,
|
|
4541
|
+
description
|
|
4542
|
+
});
|
|
1933
4543
|
}
|
|
1934
|
-
} catch (err) {
|
|
1935
|
-
}
|
|
1936
|
-
const resolvedVersion = await readSkillVersion(skillDir);
|
|
1937
|
-
if (resolvedVersion) skillVersion = resolvedVersion;
|
|
1938
|
-
if (isPlatform) {
|
|
1939
|
-
list.push({
|
|
1940
|
-
code: e.name,
|
|
1941
|
-
isPlatform: true,
|
|
1942
|
-
isBuiltIn,
|
|
1943
|
-
version: skillVersion,
|
|
1944
|
-
name,
|
|
1945
|
-
description,
|
|
1946
|
-
publishedAt: metaData?.publishedAt
|
|
1947
|
-
});
|
|
1948
|
-
} else {
|
|
1949
|
-
list.push({
|
|
1950
|
-
code: e.name,
|
|
1951
|
-
isPlatform: false,
|
|
1952
|
-
isBuiltIn,
|
|
1953
|
-
version: skillVersion,
|
|
1954
|
-
name,
|
|
1955
|
-
description
|
|
1956
|
-
});
|
|
1957
4544
|
}
|
|
1958
4545
|
}
|
|
1959
|
-
this.reply(replyId, { success: true, data:
|
|
4546
|
+
this.reply(replyId, { success: true, data: [...skillsByCode.values()], action });
|
|
1960
4547
|
} else if (action === "UPDATE_SKILL") {
|
|
1961
4548
|
if (!safeCode) throw new Error("Missing code parameter");
|
|
1962
4549
|
const delayMs = Math.random() * 5e3;
|
|
4550
|
+
const syncBuiltInTemplate = !gatewaySkillCommand && shouldSyncBuiltInTemplate(action, isBuiltIn);
|
|
1963
4551
|
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`, {
|
|
4552
|
+
this.appendLogToFile("INFO", "Command", `Scheduled UPDATE_SKILL`, {
|
|
4553
|
+
userId,
|
|
4554
|
+
code: safeCode,
|
|
4555
|
+
version,
|
|
4556
|
+
isBuiltIn,
|
|
4557
|
+
installScope,
|
|
4558
|
+
syncBuiltInTemplate,
|
|
4559
|
+
delayMs: Math.round(delayMs)
|
|
4560
|
+
});
|
|
1965
4561
|
setTimeout(async () => {
|
|
1966
4562
|
try {
|
|
1967
|
-
await this.
|
|
4563
|
+
const targetDir = gatewaySkillCommand ? resolveGatewaySkillTarget() : await this.resolveRegularSkillTarget(userId);
|
|
4564
|
+
const additionalTargetDirs = syncBuiltInTemplate ? [path9.join(openclawHome(), "workspace-xgjk-assistant-template", "skills")] : [];
|
|
4565
|
+
const userSkillRoot = pureId ? await findInstalledExpertSkillsRoot(openclawHome(), pureId, safeCode) : void 0;
|
|
4566
|
+
if (userSkillRoot) additionalTargetDirs.push(userSkillRoot);
|
|
4567
|
+
const result = await this.options.updater.manualInstall({
|
|
1968
4568
|
code: safeCode,
|
|
1969
4569
|
url,
|
|
1970
4570
|
version,
|
|
1971
4571
|
force: true,
|
|
1972
|
-
targetDir
|
|
4572
|
+
targetDir,
|
|
4573
|
+
additionalTargetDirs,
|
|
4574
|
+
trace: this.createInstallTrace({
|
|
4575
|
+
action,
|
|
4576
|
+
replyId,
|
|
4577
|
+
userId,
|
|
4578
|
+
code: safeCode,
|
|
4579
|
+
isBuiltIn,
|
|
4580
|
+
syncBuiltInTemplate
|
|
4581
|
+
})
|
|
4582
|
+
});
|
|
4583
|
+
this.appendLogToFile(result.success ? "INFO" : "ERROR", "Command", `UPDATE_SKILL completed`, {
|
|
4584
|
+
userId,
|
|
4585
|
+
code: safeCode,
|
|
4586
|
+
replyId,
|
|
4587
|
+
success: result.success,
|
|
4588
|
+
message: result.message,
|
|
4589
|
+
syncBuiltInTemplate
|
|
1973
4590
|
});
|
|
1974
4591
|
if (replyId) {
|
|
1975
|
-
this.reply(replyId, {
|
|
4592
|
+
this.reply(replyId, {
|
|
4593
|
+
success: result.success,
|
|
4594
|
+
message: result.message,
|
|
4595
|
+
action,
|
|
4596
|
+
data: { code: safeCode, version, installScope: gatewaySkillCommand ? "gateway" : "agent" }
|
|
4597
|
+
});
|
|
1976
4598
|
}
|
|
1977
4599
|
} catch (e) {
|
|
4600
|
+
this.appendLogToFile("ERROR", "Command", `UPDATE_SKILL threw`, {
|
|
4601
|
+
userId,
|
|
4602
|
+
code: safeCode,
|
|
4603
|
+
replyId,
|
|
4604
|
+
message: e?.message || String(e),
|
|
4605
|
+
stack: e?.stack
|
|
4606
|
+
});
|
|
1978
4607
|
if (replyId) this.reply(replyId, { success: false, message: e.message, action });
|
|
1979
4608
|
}
|
|
1980
4609
|
}, delayMs);
|
|
@@ -1983,28 +4612,52 @@ var GatewayWsClient = class {
|
|
|
1983
4612
|
const { name, version: version2, downloadUrl, skills } = msg;
|
|
1984
4613
|
console.log(`[skill-logger-plugin][WS] Executing INSTALL_EXPERT for user ${userId}, code: ${safeCode}`);
|
|
1985
4614
|
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
|
-
|
|
4615
|
+
const userSkillRoot = path9.join(openclawHome(), `workspace-assistant-${pureId}`, ".user");
|
|
4616
|
+
const expertTarget = path9.join(userSkillRoot, "experts", safeCode);
|
|
4617
|
+
let skipInstall = false;
|
|
4618
|
+
const metaPath = path9.join(expertTarget, ".meta.json");
|
|
4619
|
+
try {
|
|
4620
|
+
const raw = await fs8.readFile(metaPath, "utf-8");
|
|
4621
|
+
const existing = JSON.parse(raw);
|
|
4622
|
+
if (existing.version && existing.version === (version2 || "1.0.0")) {
|
|
4623
|
+
skipInstall = true;
|
|
4624
|
+
}
|
|
4625
|
+
} catch {
|
|
4626
|
+
}
|
|
4627
|
+
if (!skipInstall) {
|
|
4628
|
+
await fs8.mkdir(path9.dirname(expertTarget), { recursive: true });
|
|
4629
|
+
const expertResult = await this.options.updater.installExpertZipFromUrl(downloadUrl, expertTarget);
|
|
4630
|
+
if (!expertResult.success) {
|
|
4631
|
+
throw new Error(`\u4E13\u5BB6\u5B89\u88C5\u5931\u8D25: ${expertResult.message}`);
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
const meta = { code: safeCode, name, version: version2 || "1.0.0", installedAt: Date.now() };
|
|
4635
|
+
await fs8.writeFile(metaPath, JSON.stringify(meta, null, 2));
|
|
4636
|
+
const skillTargetRoot = path9.join(userSkillRoot, "skills");
|
|
4637
|
+
await fs8.mkdir(skillTargetRoot, { recursive: true });
|
|
1995
4638
|
const skillResults = [];
|
|
1996
4639
|
if (Array.isArray(skills)) {
|
|
1997
4640
|
for (const sk of skills) {
|
|
1998
|
-
|
|
1999
|
-
|
|
4641
|
+
const skillCode = normalizeCommandCode(sk?.code);
|
|
4642
|
+
if (!skillCode) {
|
|
4643
|
+
skillResults.push(`${String(sk?.code || "unknown")}: \u5931\u8D25 - \u975E\u6CD5\u7684 Skill code`);
|
|
4644
|
+
continue;
|
|
4645
|
+
}
|
|
4646
|
+
if (!sk.downloadUrl) {
|
|
4647
|
+
skillResults.push(`${skillCode}: \u5931\u8D25 - \u7F3A\u5C11\u4E0B\u8F7D\u5730\u5740`);
|
|
2000
4648
|
continue;
|
|
2001
4649
|
}
|
|
2002
4650
|
try {
|
|
2003
|
-
const
|
|
2004
|
-
|
|
2005
|
-
|
|
4651
|
+
const result = await this.options.updater.manualInstall({
|
|
4652
|
+
code: skillCode,
|
|
4653
|
+
url: sk.downloadUrl,
|
|
4654
|
+
version: sk.version,
|
|
4655
|
+
force: true,
|
|
4656
|
+
targetDir: skillTargetRoot
|
|
4657
|
+
});
|
|
4658
|
+
skillResults.push(`${skillCode}: ${result.success ? "\u6210\u529F" : "\u5931\u8D25 - " + result.message}`);
|
|
2006
4659
|
} catch (e) {
|
|
2007
|
-
skillResults.push(`${
|
|
4660
|
+
skillResults.push(`${skillCode}: \u5931\u8D25 - ${e.message}`);
|
|
2008
4661
|
}
|
|
2009
4662
|
}
|
|
2010
4663
|
}
|
|
@@ -2014,48 +4667,42 @@ var GatewayWsClient = class {
|
|
|
2014
4667
|
action,
|
|
2015
4668
|
data: { expertCode: safeCode, skills: skillResults }
|
|
2016
4669
|
});
|
|
2017
|
-
} else if (action === "
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
4670
|
+
} else if (action === "UNINSTALL_EXPERT") {
|
|
4671
|
+
if (!safeCode) throw new Error("Missing code parameter");
|
|
4672
|
+
console.log(`[skill-logger-plugin][WS] Executing UNINSTALL_EXPERT for user ${userId}, code: ${safeCode}`);
|
|
4673
|
+
this.appendLogToFile("INFO", "Command", `UNINSTALL_EXPERT received`, { userId, code: safeCode });
|
|
4674
|
+
const expertPath = path9.join(openclawHome(), `workspace-assistant-${pureId}`, ".user", "experts", safeCode);
|
|
4675
|
+
await fs8.rm(expertPath, { recursive: true, force: true });
|
|
4676
|
+
this.reply(replyId, { success: true, message: `\u4E13\u5BB6 ${safeCode} \u5DF2\u5378\u8F7D`, action });
|
|
4677
|
+
} else if (action === "LIST_EXPERTS") {
|
|
4678
|
+
console.log(`[skill-logger-plugin][WS] Executing LIST_EXPERTS for user ${userId}`);
|
|
4679
|
+
this.appendLogToFile("INFO", "Command", `LIST_EXPERTS received`, { userId });
|
|
4680
|
+
const expertsDir = path9.join(openclawHome(), `workspace-assistant-${pureId}`, ".user", "experts");
|
|
4681
|
+
const list = [];
|
|
2023
4682
|
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();
|
|
4683
|
+
const stat = await fs8.stat(expertsDir);
|
|
4684
|
+
if (stat.isDirectory()) {
|
|
4685
|
+
const entries = await fs8.readdir(expertsDir, { withFileTypes: true });
|
|
4686
|
+
for (const e of entries) {
|
|
4687
|
+
if (!e.isDirectory()) continue;
|
|
4688
|
+
const metaPath = path9.join(expertsDir, e.name, ".meta.json");
|
|
4689
|
+
try {
|
|
4690
|
+
const raw = await fs8.readFile(metaPath, "utf-8");
|
|
4691
|
+
const meta = JSON.parse(raw);
|
|
4692
|
+
list.push({
|
|
4693
|
+
code: meta.code || e.name,
|
|
4694
|
+
name: meta.name || e.name,
|
|
4695
|
+
version: meta.version || "",
|
|
4696
|
+
installedAt: meta.installedAt
|
|
4697
|
+
});
|
|
4698
|
+
} catch {
|
|
4699
|
+
list.push({ code: e.name, name: e.name, version: "" });
|
|
2051
4700
|
}
|
|
2052
4701
|
}
|
|
2053
4702
|
}
|
|
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 });
|
|
4703
|
+
} catch {
|
|
2058
4704
|
}
|
|
4705
|
+
this.reply(replyId, { success: true, data: list, action });
|
|
2059
4706
|
} else {
|
|
2060
4707
|
console.warn(`[skill-logger-plugin][WS] Unknown action: ${action}`);
|
|
2061
4708
|
this.appendLogToFile("WARN", "Command", `Unknown action: ${action}`);
|
|
@@ -2072,7 +4719,13 @@ var GatewayWsClient = class {
|
|
|
2072
4719
|
this.appendLogToFile("WARN", "Command", `Cannot reply: WS closed or missing replyId`, { replyId });
|
|
2073
4720
|
return;
|
|
2074
4721
|
}
|
|
2075
|
-
this.ws.send(JSON.stringify({ type: "REPLY", replyId, ...payload }))
|
|
4722
|
+
this.ws.send(JSON.stringify({ type: "REPLY", replyId, ...payload }), (err) => {
|
|
4723
|
+
if (err) {
|
|
4724
|
+
this.appendLogToFile("ERROR", "Command", `Reply send failed`, { replyId, message: err.message });
|
|
4725
|
+
return;
|
|
4726
|
+
}
|
|
4727
|
+
this.appendLogToFile("INFO", "Command", `Reply sent`, { replyId });
|
|
4728
|
+
});
|
|
2076
4729
|
}
|
|
2077
4730
|
destroy() {
|
|
2078
4731
|
this.isDestroyed = true;
|
|
@@ -2088,8 +4741,8 @@ var GatewayWsClient = class {
|
|
|
2088
4741
|
};
|
|
2089
4742
|
|
|
2090
4743
|
// src/hooks.ts
|
|
2091
|
-
import
|
|
2092
|
-
import { randomUUID as
|
|
4744
|
+
import path10 from "node:path";
|
|
4745
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
2093
4746
|
var PENDING_TTL_MS = 30 * 60 * 1e3;
|
|
2094
4747
|
var PENDING_MAX = 5e3;
|
|
2095
4748
|
function toMySQLDateTime(d) {
|
|
@@ -2097,7 +4750,7 @@ function toMySQLDateTime(d) {
|
|
|
2097
4750
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
2098
4751
|
}
|
|
2099
4752
|
function isSkillMdReadPath(filePath) {
|
|
2100
|
-
return
|
|
4753
|
+
return path10.basename(filePath) === "SKILL.md";
|
|
2101
4754
|
}
|
|
2102
4755
|
function extractAppKey(event, ctx) {
|
|
2103
4756
|
try {
|
|
@@ -2207,7 +4860,7 @@ var Hooks = class {
|
|
|
2207
4860
|
}
|
|
2208
4861
|
buildPendingEvent(p, status, error, durationMs, appKey) {
|
|
2209
4862
|
return {
|
|
2210
|
-
event_id:
|
|
4863
|
+
event_id: randomUUID3(),
|
|
2211
4864
|
event_type: "function_call",
|
|
2212
4865
|
skill_name: p.skillName,
|
|
2213
4866
|
skill_version: p.skillVersion,
|
|
@@ -2237,27 +4890,6 @@ var Hooks = class {
|
|
|
2237
4890
|
this.sessionAppKeys.set(sk, rawAppKey);
|
|
2238
4891
|
}
|
|
2239
4892
|
}
|
|
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
4893
|
onBeforeToolCall(event, ctx) {
|
|
2262
4894
|
try {
|
|
2263
4895
|
this.sweepStalePending();
|
|
@@ -2298,8 +4930,8 @@ var Hooks = class {
|
|
|
2298
4930
|
if (toolName === "read") {
|
|
2299
4931
|
const filePath = params.path ?? params.file_path ?? "";
|
|
2300
4932
|
if (!isSkillMdReadPath(filePath)) return;
|
|
2301
|
-
const rootDir =
|
|
2302
|
-
const skillName = this.configSync.resolveSkillName(rootDir) ||
|
|
4933
|
+
const rootDir = path10.dirname(filePath);
|
|
4934
|
+
const skillName = this.configSync.resolveSkillName(rootDir) || path10.basename(rootDir);
|
|
2303
4935
|
if (!skillName) return;
|
|
2304
4936
|
this.debug(`Intercepted 'read' for SKILL.md. Attributed to skill: ${skillName}`);
|
|
2305
4937
|
this.recordTrigger(skillName, "inline", "read", ctx, appKey);
|
|
@@ -2384,7 +5016,7 @@ var Hooks = class {
|
|
|
2384
5016
|
/** 记 skill 触发事件 + 标记激活 + 懒拉配置。 */
|
|
2385
5017
|
recordTrigger(skillName, invokeMode, invokeTool, ctx, appKey) {
|
|
2386
5018
|
this.emit({
|
|
2387
|
-
event_id:
|
|
5019
|
+
event_id: randomUUID3(),
|
|
2388
5020
|
event_type: "skill_trigger",
|
|
2389
5021
|
skill_name: skillName,
|
|
2390
5022
|
skill_version: this.configSync.getVersion(skillName),
|
|
@@ -2404,7 +5036,7 @@ var Hooks = class {
|
|
|
2404
5036
|
}
|
|
2405
5037
|
buildFunctionCall(res, command, invokeTool, status, error, durationMs, ctx, appKey) {
|
|
2406
5038
|
return {
|
|
2407
|
-
event_id:
|
|
5039
|
+
event_id: randomUUID3(),
|
|
2408
5040
|
event_type: "function_call",
|
|
2409
5041
|
skill_name: res.skillName,
|
|
2410
5042
|
skill_version: res.skillVersion,
|
|
@@ -2446,7 +5078,7 @@ var Hooks = class {
|
|
|
2446
5078
|
return;
|
|
2447
5079
|
}
|
|
2448
5080
|
this.emit({
|
|
2449
|
-
event_id:
|
|
5081
|
+
event_id: randomUUID3(),
|
|
2450
5082
|
event_type: "function_call",
|
|
2451
5083
|
skill_name: skillName,
|
|
2452
5084
|
match_type: void 0,
|
|
@@ -2499,9 +5131,9 @@ var definition = {
|
|
|
2499
5131
|
register(api) {
|
|
2500
5132
|
let pkgVersion = "unknown";
|
|
2501
5133
|
try {
|
|
2502
|
-
const dir =
|
|
2503
|
-
const pkgPath =
|
|
2504
|
-
const pkg = JSON.parse(
|
|
5134
|
+
const dir = path11.dirname(fileURLToPath2(import.meta.url));
|
|
5135
|
+
const pkgPath = path11.join(dir, "..", "package.json");
|
|
5136
|
+
const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
|
|
2505
5137
|
if (pkg.version) pkgVersion = pkg.version;
|
|
2506
5138
|
} catch {
|
|
2507
5139
|
}
|
|
@@ -2518,34 +5150,25 @@ var definition = {
|
|
|
2518
5150
|
const configSync = new ConfigSync({ paths, getConfig, updater });
|
|
2519
5151
|
const reporter = new Reporter({ paths, getConfig });
|
|
2520
5152
|
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);
|
|
5153
|
+
let expertSkillLayoutRepair;
|
|
5154
|
+
const repairExpertSkillLayouts = () => {
|
|
5155
|
+
if (expertSkillLayoutRepair) return expertSkillLayoutRepair;
|
|
5156
|
+
expertSkillLayoutRepair = (async () => {
|
|
5157
|
+
const result = await repairNestedExpertSkillLayouts(openclawHome());
|
|
5158
|
+
if (result.repaired.length > 0) {
|
|
5159
|
+
console.log(`[skill-logger-plugin] \u5DF2\u4FEE\u590D ${result.repaired.length} \u4E2A\u4E13\u5BB6 Skill \u5D4C\u5957\u76EE\u5F55`);
|
|
2546
5160
|
}
|
|
2547
|
-
|
|
2548
|
-
|
|
5161
|
+
for (const skippedPath of result.skipped) {
|
|
5162
|
+
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}`);
|
|
5163
|
+
}
|
|
5164
|
+
for (const error of result.errors) {
|
|
5165
|
+
console.warn(`[skill-logger-plugin] \u4FEE\u590D\u4E13\u5BB6 Skill \u76EE\u5F55\u5931\u8D25: ${error.path}`, error.message);
|
|
5166
|
+
}
|
|
5167
|
+
})().finally(() => {
|
|
5168
|
+
expertSkillLayoutRepair = void 0;
|
|
5169
|
+
});
|
|
5170
|
+
return expertSkillLayoutRepair;
|
|
5171
|
+
};
|
|
2549
5172
|
let reconcileTimer;
|
|
2550
5173
|
const sessionUpdatedSkills = /* @__PURE__ */ new Set();
|
|
2551
5174
|
api.on("message_received", (event, ctx) => {
|
|
@@ -2553,10 +5176,9 @@ var definition = {
|
|
|
2553
5176
|
hooks.onMessageReceived(event, ctx);
|
|
2554
5177
|
});
|
|
2555
5178
|
api.on("before_prompt_build", () => {
|
|
2556
|
-
let appendStr = "
|
|
5179
|
+
let appendStr = "";
|
|
2557
5180
|
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`;
|
|
5181
|
+
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
5182
|
}
|
|
2561
5183
|
return { appendSystemContext: appendStr.trim() };
|
|
2562
5184
|
});
|
|
@@ -2597,9 +5219,8 @@ var definition = {
|
|
|
2597
5219
|
enableFileLog: currentConfig2.enableFileLog
|
|
2598
5220
|
// 将日志开关透传给客户端模块
|
|
2599
5221
|
});
|
|
2600
|
-
wsClient.connect();
|
|
2601
5222
|
}
|
|
2602
|
-
void configSync.load().then(() => configSync.reconcile()).catch((err) => console.warn("[skill-logger-plugin] \u542F\u52A8\u521D\u59CB\u5316\u5F02\u5E38", err));
|
|
5223
|
+
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
5224
|
reporter.startTimer();
|
|
2604
5225
|
if (!reconcileTimer) {
|
|
2605
5226
|
reconcileTimer = setInterval(() => void configSync.reconcile(), RECONCILE_INTERVAL_MS);
|