@automatify-au/cli 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +103 -27
  2. package/dist/automatify.js +1669 -20
  3. package/package.json +5 -1
@@ -1,4 +1,983 @@
1
1
  #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
33
+
34
+ // ../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs
35
+ var require_dist = __commonJS({
36
+ "../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs"(exports, module) {
37
+ "use strict";
38
+ function getDefaultExportFromCjs(x) {
39
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
40
+ }
41
+ var CRC_TABLE = new Int32Array([
42
+ 0,
43
+ 1996959894,
44
+ 3993919788,
45
+ 2567524794,
46
+ 124634137,
47
+ 1886057615,
48
+ 3915621685,
49
+ 2657392035,
50
+ 249268274,
51
+ 2044508324,
52
+ 3772115230,
53
+ 2547177864,
54
+ 162941995,
55
+ 2125561021,
56
+ 3887607047,
57
+ 2428444049,
58
+ 498536548,
59
+ 1789927666,
60
+ 4089016648,
61
+ 2227061214,
62
+ 450548861,
63
+ 1843258603,
64
+ 4107580753,
65
+ 2211677639,
66
+ 325883990,
67
+ 1684777152,
68
+ 4251122042,
69
+ 2321926636,
70
+ 335633487,
71
+ 1661365465,
72
+ 4195302755,
73
+ 2366115317,
74
+ 997073096,
75
+ 1281953886,
76
+ 3579855332,
77
+ 2724688242,
78
+ 1006888145,
79
+ 1258607687,
80
+ 3524101629,
81
+ 2768942443,
82
+ 901097722,
83
+ 1119000684,
84
+ 3686517206,
85
+ 2898065728,
86
+ 853044451,
87
+ 1172266101,
88
+ 3705015759,
89
+ 2882616665,
90
+ 651767980,
91
+ 1373503546,
92
+ 3369554304,
93
+ 3218104598,
94
+ 565507253,
95
+ 1454621731,
96
+ 3485111705,
97
+ 3099436303,
98
+ 671266974,
99
+ 1594198024,
100
+ 3322730930,
101
+ 2970347812,
102
+ 795835527,
103
+ 1483230225,
104
+ 3244367275,
105
+ 3060149565,
106
+ 1994146192,
107
+ 31158534,
108
+ 2563907772,
109
+ 4023717930,
110
+ 1907459465,
111
+ 112637215,
112
+ 2680153253,
113
+ 3904427059,
114
+ 2013776290,
115
+ 251722036,
116
+ 2517215374,
117
+ 3775830040,
118
+ 2137656763,
119
+ 141376813,
120
+ 2439277719,
121
+ 3865271297,
122
+ 1802195444,
123
+ 476864866,
124
+ 2238001368,
125
+ 4066508878,
126
+ 1812370925,
127
+ 453092731,
128
+ 2181625025,
129
+ 4111451223,
130
+ 1706088902,
131
+ 314042704,
132
+ 2344532202,
133
+ 4240017532,
134
+ 1658658271,
135
+ 366619977,
136
+ 2362670323,
137
+ 4224994405,
138
+ 1303535960,
139
+ 984961486,
140
+ 2747007092,
141
+ 3569037538,
142
+ 1256170817,
143
+ 1037604311,
144
+ 2765210733,
145
+ 3554079995,
146
+ 1131014506,
147
+ 879679996,
148
+ 2909243462,
149
+ 3663771856,
150
+ 1141124467,
151
+ 855842277,
152
+ 2852801631,
153
+ 3708648649,
154
+ 1342533948,
155
+ 654459306,
156
+ 3188396048,
157
+ 3373015174,
158
+ 1466479909,
159
+ 544179635,
160
+ 3110523913,
161
+ 3462522015,
162
+ 1591671054,
163
+ 702138776,
164
+ 2966460450,
165
+ 3352799412,
166
+ 1504918807,
167
+ 783551873,
168
+ 3082640443,
169
+ 3233442989,
170
+ 3988292384,
171
+ 2596254646,
172
+ 62317068,
173
+ 1957810842,
174
+ 3939845945,
175
+ 2647816111,
176
+ 81470997,
177
+ 1943803523,
178
+ 3814918930,
179
+ 2489596804,
180
+ 225274430,
181
+ 2053790376,
182
+ 3826175755,
183
+ 2466906013,
184
+ 167816743,
185
+ 2097651377,
186
+ 4027552580,
187
+ 2265490386,
188
+ 503444072,
189
+ 1762050814,
190
+ 4150417245,
191
+ 2154129355,
192
+ 426522225,
193
+ 1852507879,
194
+ 4275313526,
195
+ 2312317920,
196
+ 282753626,
197
+ 1742555852,
198
+ 4189708143,
199
+ 2394877945,
200
+ 397917763,
201
+ 1622183637,
202
+ 3604390888,
203
+ 2714866558,
204
+ 953729732,
205
+ 1340076626,
206
+ 3518719985,
207
+ 2797360999,
208
+ 1068828381,
209
+ 1219638859,
210
+ 3624741850,
211
+ 2936675148,
212
+ 906185462,
213
+ 1090812512,
214
+ 3747672003,
215
+ 2825379669,
216
+ 829329135,
217
+ 1181335161,
218
+ 3412177804,
219
+ 3160834842,
220
+ 628085408,
221
+ 1382605366,
222
+ 3423369109,
223
+ 3138078467,
224
+ 570562233,
225
+ 1426400815,
226
+ 3317316542,
227
+ 2998733608,
228
+ 733239954,
229
+ 1555261956,
230
+ 3268935591,
231
+ 3050360625,
232
+ 752459403,
233
+ 1541320221,
234
+ 2607071920,
235
+ 3965973030,
236
+ 1969922972,
237
+ 40735498,
238
+ 2617837225,
239
+ 3943577151,
240
+ 1913087877,
241
+ 83908371,
242
+ 2512341634,
243
+ 3803740692,
244
+ 2075208622,
245
+ 213261112,
246
+ 2463272603,
247
+ 3855990285,
248
+ 2094854071,
249
+ 198958881,
250
+ 2262029012,
251
+ 4057260610,
252
+ 1759359992,
253
+ 534414190,
254
+ 2176718541,
255
+ 4139329115,
256
+ 1873836001,
257
+ 414664567,
258
+ 2282248934,
259
+ 4279200368,
260
+ 1711684554,
261
+ 285281116,
262
+ 2405801727,
263
+ 4167216745,
264
+ 1634467795,
265
+ 376229701,
266
+ 2685067896,
267
+ 3608007406,
268
+ 1308918612,
269
+ 956543938,
270
+ 2808555105,
271
+ 3495958263,
272
+ 1231636301,
273
+ 1047427035,
274
+ 2932959818,
275
+ 3654703836,
276
+ 1088359270,
277
+ 936918e3,
278
+ 2847714899,
279
+ 3736837829,
280
+ 1202900863,
281
+ 817233897,
282
+ 3183342108,
283
+ 3401237130,
284
+ 1404277552,
285
+ 615818150,
286
+ 3134207493,
287
+ 3453421203,
288
+ 1423857449,
289
+ 601450431,
290
+ 3009837614,
291
+ 3294710456,
292
+ 1567103746,
293
+ 711928724,
294
+ 3020668471,
295
+ 3272380065,
296
+ 1510334235,
297
+ 755167117
298
+ ]);
299
+ function ensureBuffer(input) {
300
+ if (Buffer.isBuffer(input)) {
301
+ return input;
302
+ }
303
+ if (typeof input === "number") {
304
+ return Buffer.alloc(input);
305
+ } else if (typeof input === "string") {
306
+ return Buffer.from(input);
307
+ } else {
308
+ throw new Error("input must be buffer, number, or string, received " + typeof input);
309
+ }
310
+ }
311
+ function bufferizeInt(num) {
312
+ const tmp = ensureBuffer(4);
313
+ tmp.writeInt32BE(num, 0);
314
+ return tmp;
315
+ }
316
+ function _crc32(buf, previous) {
317
+ buf = ensureBuffer(buf);
318
+ if (Buffer.isBuffer(previous)) {
319
+ previous = previous.readUInt32BE(0);
320
+ }
321
+ let crc = ~~previous ^ -1;
322
+ for (var n = 0; n < buf.length; n++) {
323
+ crc = CRC_TABLE[(crc ^ buf[n]) & 255] ^ crc >>> 8;
324
+ }
325
+ return crc ^ -1;
326
+ }
327
+ function crc32() {
328
+ return bufferizeInt(_crc32.apply(null, arguments));
329
+ }
330
+ crc32.signed = function() {
331
+ return _crc32.apply(null, arguments);
332
+ };
333
+ crc32.unsigned = function() {
334
+ return _crc32.apply(null, arguments) >>> 0;
335
+ };
336
+ var bufferCrc32 = crc32;
337
+ var index = /* @__PURE__ */ getDefaultExportFromCjs(bufferCrc32);
338
+ module.exports = index;
339
+ }
340
+ });
341
+
342
+ // ../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js
343
+ var require_yazl = __commonJS({
344
+ "../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js"(exports) {
345
+ var fs = __require("fs");
346
+ var Transform = __require("stream").Transform;
347
+ var PassThrough = __require("stream").PassThrough;
348
+ var zlib = __require("zlib");
349
+ var util = __require("util");
350
+ var EventEmitter = __require("events").EventEmitter;
351
+ var errorMonitor = __require("events").errorMonitor;
352
+ var crc32 = require_dist();
353
+ exports.ZipFile = ZipFile2;
354
+ exports.dateToDosDateTime = dateToDosDateTime;
355
+ util.inherits(ZipFile2, EventEmitter);
356
+ function ZipFile2() {
357
+ this.outputStream = new PassThrough();
358
+ this.entries = [];
359
+ this.outputStreamCursor = 0;
360
+ this.ended = false;
361
+ this.allDone = false;
362
+ this.forceZip64Eocd = false;
363
+ this.errored = false;
364
+ this.on(errorMonitor, function() {
365
+ this.errored = true;
366
+ });
367
+ }
368
+ ZipFile2.prototype.addFile = function(realPath, metadataPath, options) {
369
+ var self = this;
370
+ metadataPath = validateMetadataPath(metadataPath, false);
371
+ if (options == null) options = {};
372
+ if (shouldIgnoreAdding(self)) return;
373
+ var entry = new Entry(metadataPath, false, options);
374
+ self.entries.push(entry);
375
+ fs.stat(realPath, function(err, stats) {
376
+ if (err) return self.emit("error", err);
377
+ if (!stats.isFile()) return self.emit("error", new Error("not a file: " + realPath));
378
+ entry.uncompressedSize = stats.size;
379
+ if (options.mtime == null) entry.setLastModDate(stats.mtime);
380
+ if (options.mode == null) entry.setFileAttributesMode(stats.mode);
381
+ entry.setFileDataPumpFunction(function() {
382
+ var readStream = fs.createReadStream(realPath);
383
+ entry.state = Entry.FILE_DATA_IN_PROGRESS;
384
+ readStream.on("error", function(err2) {
385
+ self.emit("error", err2);
386
+ });
387
+ pumpFileDataReadStream(self, entry, readStream);
388
+ });
389
+ pumpEntries(self);
390
+ });
391
+ };
392
+ ZipFile2.prototype.addReadStream = function(readStream, metadataPath, options) {
393
+ this.addReadStreamLazy(metadataPath, options, function(cb) {
394
+ cb(null, readStream);
395
+ });
396
+ };
397
+ ZipFile2.prototype.addReadStreamLazy = function(metadataPath, options, getReadStreamFunction) {
398
+ var self = this;
399
+ if (typeof options === "function") {
400
+ getReadStreamFunction = options;
401
+ options = null;
402
+ }
403
+ if (options == null) options = {};
404
+ metadataPath = validateMetadataPath(metadataPath, false);
405
+ if (shouldIgnoreAdding(self)) return;
406
+ var entry = new Entry(metadataPath, false, options);
407
+ self.entries.push(entry);
408
+ entry.setFileDataPumpFunction(function() {
409
+ entry.state = Entry.FILE_DATA_IN_PROGRESS;
410
+ getReadStreamFunction(function(err, readStream) {
411
+ if (err) return self.emit("error", err);
412
+ pumpFileDataReadStream(self, entry, readStream);
413
+ });
414
+ });
415
+ pumpEntries(self);
416
+ };
417
+ ZipFile2.prototype.addBuffer = function(buffer, metadataPath, options) {
418
+ var self = this;
419
+ metadataPath = validateMetadataPath(metadataPath, false);
420
+ if (buffer.length > 1073741823) throw new Error("buffer too large: " + buffer.length + " > 1073741823");
421
+ if (options == null) options = {};
422
+ if (options.size != null) throw new Error("options.size not allowed");
423
+ if (shouldIgnoreAdding(self)) return;
424
+ var entry = new Entry(metadataPath, false, options);
425
+ entry.uncompressedSize = buffer.length;
426
+ entry.crc32 = crc32.unsigned(buffer);
427
+ entry.crcAndFileSizeKnown = true;
428
+ self.entries.push(entry);
429
+ if (entry.compressionLevel === 0) {
430
+ setCompressedBuffer(buffer);
431
+ } else {
432
+ zlib.deflateRaw(buffer, { level: entry.compressionLevel }, function(err, compressedBuffer) {
433
+ setCompressedBuffer(compressedBuffer);
434
+ });
435
+ }
436
+ function setCompressedBuffer(compressedBuffer) {
437
+ entry.compressedSize = compressedBuffer.length;
438
+ entry.setFileDataPumpFunction(function() {
439
+ writeToOutputStream(self, compressedBuffer);
440
+ writeToOutputStream(self, entry.getDataDescriptor());
441
+ entry.state = Entry.FILE_DATA_DONE;
442
+ setImmediate(function() {
443
+ pumpEntries(self);
444
+ });
445
+ });
446
+ pumpEntries(self);
447
+ }
448
+ };
449
+ ZipFile2.prototype.addEmptyDirectory = function(metadataPath, options) {
450
+ var self = this;
451
+ metadataPath = validateMetadataPath(metadataPath, true);
452
+ if (options == null) options = {};
453
+ if (options.size != null) throw new Error("options.size not allowed");
454
+ if (options.compress != null) throw new Error("options.compress not allowed");
455
+ if (options.compressionLevel != null) throw new Error("options.compressionLevel not allowed");
456
+ if (shouldIgnoreAdding(self)) return;
457
+ var entry = new Entry(metadataPath, true, options);
458
+ self.entries.push(entry);
459
+ entry.setFileDataPumpFunction(function() {
460
+ writeToOutputStream(self, entry.getDataDescriptor());
461
+ entry.state = Entry.FILE_DATA_DONE;
462
+ pumpEntries(self);
463
+ });
464
+ pumpEntries(self);
465
+ };
466
+ var eocdrSignatureBuffer = bufferFrom([80, 75, 5, 6]);
467
+ ZipFile2.prototype.end = function(options, calculatedTotalSizeCallback) {
468
+ if (typeof options === "function") {
469
+ calculatedTotalSizeCallback = options;
470
+ options = null;
471
+ }
472
+ if (options == null) options = {};
473
+ if (this.ended) return;
474
+ this.ended = true;
475
+ if (this.errored) return;
476
+ this.calculatedTotalSizeCallback = calculatedTotalSizeCallback;
477
+ this.forceZip64Eocd = !!options.forceZip64Format;
478
+ if (options.comment) {
479
+ if (typeof options.comment === "string") {
480
+ this.comment = encodeCp437(options.comment);
481
+ } else {
482
+ this.comment = options.comment;
483
+ }
484
+ if (this.comment.length > 65535) throw new Error("comment is too large");
485
+ if (bufferIncludes(this.comment, eocdrSignatureBuffer)) throw new Error("comment contains end of central directory record signature");
486
+ } else {
487
+ this.comment = EMPTY_BUFFER;
488
+ }
489
+ pumpEntries(this);
490
+ };
491
+ function writeToOutputStream(self, buffer) {
492
+ self.outputStream.write(buffer);
493
+ self.outputStreamCursor += buffer.length;
494
+ }
495
+ function pumpFileDataReadStream(self, entry, readStream) {
496
+ var crc32Watcher = new Crc32Watcher();
497
+ var uncompressedSizeCounter = new ByteCounter();
498
+ var compressor = entry.compressionLevel !== 0 ? new zlib.DeflateRaw({ level: entry.compressionLevel }) : new PassThrough();
499
+ var compressedSizeCounter = new ByteCounter();
500
+ readStream.pipe(crc32Watcher).pipe(uncompressedSizeCounter).pipe(compressor).pipe(compressedSizeCounter).pipe(self.outputStream, { end: false });
501
+ compressedSizeCounter.on("end", function() {
502
+ entry.crc32 = crc32Watcher.crc32;
503
+ if (entry.uncompressedSize == null) {
504
+ entry.uncompressedSize = uncompressedSizeCounter.byteCount;
505
+ } else {
506
+ if (entry.uncompressedSize !== uncompressedSizeCounter.byteCount) return self.emit("error", new Error("file data stream has unexpected number of bytes"));
507
+ }
508
+ entry.compressedSize = compressedSizeCounter.byteCount;
509
+ self.outputStreamCursor += entry.compressedSize;
510
+ writeToOutputStream(self, entry.getDataDescriptor());
511
+ entry.state = Entry.FILE_DATA_DONE;
512
+ pumpEntries(self);
513
+ });
514
+ }
515
+ function determineCompressionLevel(options) {
516
+ if (options.compress != null && options.compressionLevel != null) {
517
+ if (!!options.compress !== !!options.compressionLevel) throw new Error("conflicting settings for compress and compressionLevel");
518
+ }
519
+ if (options.compressionLevel != null) return options.compressionLevel;
520
+ if (options.compress === false) return 0;
521
+ return 6;
522
+ }
523
+ function pumpEntries(self) {
524
+ if (self.allDone || self.errored) return;
525
+ if (self.ended && self.calculatedTotalSizeCallback != null) {
526
+ var calculatedTotalSize = calculateTotalSize(self);
527
+ if (calculatedTotalSize != null) {
528
+ self.calculatedTotalSizeCallback(calculatedTotalSize);
529
+ self.calculatedTotalSizeCallback = null;
530
+ }
531
+ }
532
+ var entry = getFirstNotDoneEntry();
533
+ function getFirstNotDoneEntry() {
534
+ for (var i = 0; i < self.entries.length; i++) {
535
+ var entry2 = self.entries[i];
536
+ if (entry2.state < Entry.FILE_DATA_DONE) return entry2;
537
+ }
538
+ return null;
539
+ }
540
+ if (entry != null) {
541
+ if (entry.state < Entry.READY_TO_PUMP_FILE_DATA) return;
542
+ if (entry.state === Entry.FILE_DATA_IN_PROGRESS) return;
543
+ entry.relativeOffsetOfLocalHeader = self.outputStreamCursor;
544
+ var localFileHeader = entry.getLocalFileHeader();
545
+ writeToOutputStream(self, localFileHeader);
546
+ entry.doFileDataPump();
547
+ } else {
548
+ if (self.ended) {
549
+ self.offsetOfStartOfCentralDirectory = self.outputStreamCursor;
550
+ self.entries.forEach(function(entry2) {
551
+ var centralDirectoryRecord = entry2.getCentralDirectoryRecord();
552
+ writeToOutputStream(self, centralDirectoryRecord);
553
+ });
554
+ writeToOutputStream(self, getEndOfCentralDirectoryRecord(self));
555
+ self.outputStream.end();
556
+ self.allDone = true;
557
+ }
558
+ }
559
+ }
560
+ function calculateTotalSize(self) {
561
+ var pretendOutputCursor = 0;
562
+ var centralDirectorySize = 0;
563
+ for (var i = 0; i < self.entries.length; i++) {
564
+ var entry = self.entries[i];
565
+ if (entry.compressionLevel !== 0) return -1;
566
+ if (entry.state >= Entry.READY_TO_PUMP_FILE_DATA) {
567
+ if (entry.uncompressedSize == null) return -1;
568
+ } else {
569
+ if (entry.uncompressedSize == null) return null;
570
+ }
571
+ entry.relativeOffsetOfLocalHeader = pretendOutputCursor;
572
+ var useZip64Format = entry.useZip64Format();
573
+ pretendOutputCursor += LOCAL_FILE_HEADER_FIXED_SIZE + entry.utf8FileName.length;
574
+ pretendOutputCursor += entry.uncompressedSize;
575
+ if (!entry.crcAndFileSizeKnown) {
576
+ if (useZip64Format) {
577
+ pretendOutputCursor += ZIP64_DATA_DESCRIPTOR_SIZE;
578
+ } else {
579
+ pretendOutputCursor += DATA_DESCRIPTOR_SIZE;
580
+ }
581
+ }
582
+ centralDirectorySize += CENTRAL_DIRECTORY_RECORD_FIXED_SIZE + entry.utf8FileName.length + entry.fileComment.length;
583
+ if (!entry.forceDosTimestamp) {
584
+ centralDirectorySize += INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE;
585
+ }
586
+ if (useZip64Format) {
587
+ centralDirectorySize += ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE;
588
+ }
589
+ }
590
+ var endOfCentralDirectorySize = 0;
591
+ if (self.forceZip64Eocd || self.entries.length >= 65535 || centralDirectorySize >= 65535 || pretendOutputCursor >= 4294967295) {
592
+ endOfCentralDirectorySize += ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE;
593
+ }
594
+ endOfCentralDirectorySize += END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length;
595
+ return pretendOutputCursor + centralDirectorySize + endOfCentralDirectorySize;
596
+ }
597
+ function shouldIgnoreAdding(self) {
598
+ if (self.ended) throw new Error("cannot add entries after calling end()");
599
+ if (self.errored) return true;
600
+ return false;
601
+ }
602
+ var ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 56;
603
+ var ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE = 20;
604
+ var END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 22;
605
+ function getEndOfCentralDirectoryRecord(self, actuallyJustTellMeHowLongItWouldBe) {
606
+ var needZip64Format = false;
607
+ var normalEntriesLength = self.entries.length;
608
+ if (self.forceZip64Eocd || self.entries.length >= 65535) {
609
+ normalEntriesLength = 65535;
610
+ needZip64Format = true;
611
+ }
612
+ var sizeOfCentralDirectory = self.outputStreamCursor - self.offsetOfStartOfCentralDirectory;
613
+ var normalSizeOfCentralDirectory = sizeOfCentralDirectory;
614
+ if (self.forceZip64Eocd || sizeOfCentralDirectory >= 4294967295) {
615
+ normalSizeOfCentralDirectory = 4294967295;
616
+ needZip64Format = true;
617
+ }
618
+ var normalOffsetOfStartOfCentralDirectory = self.offsetOfStartOfCentralDirectory;
619
+ if (self.forceZip64Eocd || self.offsetOfStartOfCentralDirectory >= 4294967295) {
620
+ normalOffsetOfStartOfCentralDirectory = 4294967295;
621
+ needZip64Format = true;
622
+ }
623
+ if (actuallyJustTellMeHowLongItWouldBe) {
624
+ if (needZip64Format) {
625
+ return ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE + END_OF_CENTRAL_DIRECTORY_RECORD_SIZE;
626
+ } else {
627
+ return END_OF_CENTRAL_DIRECTORY_RECORD_SIZE;
628
+ }
629
+ }
630
+ var eocdrBuffer = bufferAlloc(END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length);
631
+ eocdrBuffer.writeUInt32LE(101010256, 0);
632
+ eocdrBuffer.writeUInt16LE(0, 4);
633
+ eocdrBuffer.writeUInt16LE(0, 6);
634
+ eocdrBuffer.writeUInt16LE(normalEntriesLength, 8);
635
+ eocdrBuffer.writeUInt16LE(normalEntriesLength, 10);
636
+ eocdrBuffer.writeUInt32LE(normalSizeOfCentralDirectory, 12);
637
+ eocdrBuffer.writeUInt32LE(normalOffsetOfStartOfCentralDirectory, 16);
638
+ eocdrBuffer.writeUInt16LE(self.comment.length, 20);
639
+ self.comment.copy(eocdrBuffer, 22);
640
+ if (!needZip64Format) return eocdrBuffer;
641
+ var zip64EocdrBuffer = bufferAlloc(ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE);
642
+ zip64EocdrBuffer.writeUInt32LE(101075792, 0);
643
+ writeUInt64LE(zip64EocdrBuffer, ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE - 12, 4);
644
+ zip64EocdrBuffer.writeUInt16LE(VERSION_MADE_BY, 12);
645
+ zip64EocdrBuffer.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT_ZIP64, 14);
646
+ zip64EocdrBuffer.writeUInt32LE(0, 16);
647
+ zip64EocdrBuffer.writeUInt32LE(0, 20);
648
+ writeUInt64LE(zip64EocdrBuffer, self.entries.length, 24);
649
+ writeUInt64LE(zip64EocdrBuffer, self.entries.length, 32);
650
+ writeUInt64LE(zip64EocdrBuffer, sizeOfCentralDirectory, 40);
651
+ writeUInt64LE(zip64EocdrBuffer, self.offsetOfStartOfCentralDirectory, 48);
652
+ var zip64EocdlBuffer = bufferAlloc(ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE);
653
+ zip64EocdlBuffer.writeUInt32LE(117853008, 0);
654
+ zip64EocdlBuffer.writeUInt32LE(0, 4);
655
+ writeUInt64LE(zip64EocdlBuffer, self.outputStreamCursor, 8);
656
+ zip64EocdlBuffer.writeUInt32LE(1, 16);
657
+ return Buffer.concat([
658
+ zip64EocdrBuffer,
659
+ zip64EocdlBuffer,
660
+ eocdrBuffer
661
+ ]);
662
+ }
663
+ function validateMetadataPath(metadataPath, isDirectory) {
664
+ if (metadataPath === "") throw new Error("empty metadataPath");
665
+ metadataPath = metadataPath.replace(/\\/g, "/");
666
+ if (/^[a-zA-Z]:/.test(metadataPath) || /^\//.test(metadataPath)) throw new Error("absolute path: " + metadataPath);
667
+ if (metadataPath.split("/").indexOf("..") !== -1) throw new Error("invalid relative path: " + metadataPath);
668
+ var looksLikeDirectory = /\/$/.test(metadataPath);
669
+ if (isDirectory) {
670
+ if (!looksLikeDirectory) metadataPath += "/";
671
+ } else {
672
+ if (looksLikeDirectory) throw new Error("file path cannot end with '/': " + metadataPath);
673
+ }
674
+ return metadataPath;
675
+ }
676
+ var EMPTY_BUFFER = bufferAlloc(0);
677
+ function Entry(metadataPath, isDirectory, options) {
678
+ this.utf8FileName = bufferFrom(metadataPath);
679
+ if (this.utf8FileName.length > 65535) throw new Error("utf8 file name too long. " + utf8FileName.length + " > 65535");
680
+ this.isDirectory = isDirectory;
681
+ this.state = Entry.WAITING_FOR_METADATA;
682
+ this.setLastModDate(options.mtime != null ? options.mtime : /* @__PURE__ */ new Date());
683
+ this.forceDosTimestamp = !!options.forceDosTimestamp;
684
+ if (options.mode != null) {
685
+ this.setFileAttributesMode(options.mode);
686
+ } else {
687
+ this.setFileAttributesMode(isDirectory ? 16893 : 33204);
688
+ }
689
+ if (isDirectory) {
690
+ this.crcAndFileSizeKnown = true;
691
+ this.crc32 = 0;
692
+ this.uncompressedSize = 0;
693
+ this.compressedSize = 0;
694
+ } else {
695
+ this.crcAndFileSizeKnown = false;
696
+ this.crc32 = null;
697
+ this.uncompressedSize = null;
698
+ this.compressedSize = null;
699
+ if (options.size != null) this.uncompressedSize = options.size;
700
+ }
701
+ if (isDirectory) {
702
+ this.compressionLevel = 0;
703
+ } else {
704
+ this.compressionLevel = determineCompressionLevel(options);
705
+ }
706
+ this.forceZip64Format = !!options.forceZip64Format;
707
+ if (options.fileComment) {
708
+ if (typeof options.fileComment === "string") {
709
+ this.fileComment = bufferFrom(options.fileComment, "utf-8");
710
+ } else {
711
+ this.fileComment = options.fileComment;
712
+ }
713
+ if (this.fileComment.length > 65535) throw new Error("fileComment is too large");
714
+ } else {
715
+ this.fileComment = EMPTY_BUFFER;
716
+ }
717
+ }
718
+ Entry.WAITING_FOR_METADATA = 0;
719
+ Entry.READY_TO_PUMP_FILE_DATA = 1;
720
+ Entry.FILE_DATA_IN_PROGRESS = 2;
721
+ Entry.FILE_DATA_DONE = 3;
722
+ Entry.prototype.setLastModDate = function(date) {
723
+ this.mtime = date;
724
+ var dosDateTime = dateToDosDateTime(date);
725
+ this.lastModFileTime = dosDateTime.time;
726
+ this.lastModFileDate = dosDateTime.date;
727
+ };
728
+ Entry.prototype.setFileAttributesMode = function(mode) {
729
+ if ((mode & 65535) !== mode) throw new Error("invalid mode. expected: 0 <= " + mode + " <= 65535");
730
+ this.externalFileAttributes = mode << 16 >>> 0;
731
+ };
732
+ Entry.prototype.setFileDataPumpFunction = function(doFileDataPump) {
733
+ this.doFileDataPump = doFileDataPump;
734
+ this.state = Entry.READY_TO_PUMP_FILE_DATA;
735
+ };
736
+ Entry.prototype.useZip64Format = function() {
737
+ return this.forceZip64Format || this.uncompressedSize != null && this.uncompressedSize > 4294967294 || this.compressedSize != null && this.compressedSize > 4294967294 || this.relativeOffsetOfLocalHeader != null && this.relativeOffsetOfLocalHeader > 4294967294;
738
+ };
739
+ var LOCAL_FILE_HEADER_FIXED_SIZE = 30;
740
+ var VERSION_NEEDED_TO_EXTRACT_UTF8 = 20;
741
+ var VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45;
742
+ var VERSION_MADE_BY = 3 << 8 | 63;
743
+ var FILE_NAME_IS_UTF8 = 1 << 11;
744
+ var UNKNOWN_CRC32_AND_FILE_SIZES = 1 << 3;
745
+ Entry.prototype.getLocalFileHeader = function() {
746
+ var crc322 = 0;
747
+ var compressedSize = 0;
748
+ var uncompressedSize = 0;
749
+ if (this.crcAndFileSizeKnown) {
750
+ crc322 = this.crc32;
751
+ compressedSize = this.compressedSize;
752
+ uncompressedSize = this.uncompressedSize;
753
+ }
754
+ var fixedSizeStuff = bufferAlloc(LOCAL_FILE_HEADER_FIXED_SIZE);
755
+ var generalPurposeBitFlag = FILE_NAME_IS_UTF8;
756
+ if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;
757
+ fixedSizeStuff.writeUInt32LE(67324752, 0);
758
+ fixedSizeStuff.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT_UTF8, 4);
759
+ fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 6);
760
+ fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 8);
761
+ fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 10);
762
+ fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 12);
763
+ fixedSizeStuff.writeUInt32LE(crc322, 14);
764
+ fixedSizeStuff.writeUInt32LE(compressedSize, 18);
765
+ fixedSizeStuff.writeUInt32LE(uncompressedSize, 22);
766
+ fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 26);
767
+ fixedSizeStuff.writeUInt16LE(0, 28);
768
+ return Buffer.concat([
769
+ fixedSizeStuff,
770
+ // file name (variable size)
771
+ this.utf8FileName
772
+ // extra field (variable size)
773
+ // no extra fields
774
+ ]);
775
+ };
776
+ var DATA_DESCRIPTOR_SIZE = 16;
777
+ var ZIP64_DATA_DESCRIPTOR_SIZE = 24;
778
+ Entry.prototype.getDataDescriptor = function() {
779
+ if (this.crcAndFileSizeKnown) {
780
+ return EMPTY_BUFFER;
781
+ }
782
+ if (!this.useZip64Format()) {
783
+ var buffer = bufferAlloc(DATA_DESCRIPTOR_SIZE);
784
+ buffer.writeUInt32LE(134695760, 0);
785
+ buffer.writeUInt32LE(this.crc32, 4);
786
+ buffer.writeUInt32LE(this.compressedSize, 8);
787
+ buffer.writeUInt32LE(this.uncompressedSize, 12);
788
+ return buffer;
789
+ } else {
790
+ var buffer = bufferAlloc(ZIP64_DATA_DESCRIPTOR_SIZE);
791
+ buffer.writeUInt32LE(134695760, 0);
792
+ buffer.writeUInt32LE(this.crc32, 4);
793
+ writeUInt64LE(buffer, this.compressedSize, 8);
794
+ writeUInt64LE(buffer, this.uncompressedSize, 16);
795
+ return buffer;
796
+ }
797
+ };
798
+ var CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46;
799
+ var INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE = 9;
800
+ var ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE = 28;
801
+ Entry.prototype.getCentralDirectoryRecord = function() {
802
+ var fixedSizeStuff = bufferAlloc(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE);
803
+ var generalPurposeBitFlag = FILE_NAME_IS_UTF8;
804
+ if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;
805
+ var izutefBuffer = EMPTY_BUFFER;
806
+ if (!this.forceDosTimestamp) {
807
+ izutefBuffer = bufferAlloc(INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE);
808
+ izutefBuffer.writeUInt16LE(21589, 0);
809
+ izutefBuffer.writeUInt16LE(INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE - 4, 2);
810
+ var EB_UT_FL_MTIME = 1 << 0;
811
+ var EB_UT_FL_ATIME = 1 << 1;
812
+ izutefBuffer.writeUInt8(EB_UT_FL_MTIME | EB_UT_FL_ATIME, 4);
813
+ var timestamp = Math.floor(this.mtime.getTime() / 1e3);
814
+ if (timestamp < -2147483648) timestamp = -2147483648;
815
+ if (timestamp > 2147483647) timestamp = 2147483647;
816
+ izutefBuffer.writeUInt32LE(timestamp, 5);
817
+ }
818
+ var normalCompressedSize = this.compressedSize;
819
+ var normalUncompressedSize = this.uncompressedSize;
820
+ var normalRelativeOffsetOfLocalHeader = this.relativeOffsetOfLocalHeader;
821
+ var versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_UTF8;
822
+ var zeiefBuffer = EMPTY_BUFFER;
823
+ if (this.useZip64Format()) {
824
+ normalCompressedSize = 4294967295;
825
+ normalUncompressedSize = 4294967295;
826
+ normalRelativeOffsetOfLocalHeader = 4294967295;
827
+ versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_ZIP64;
828
+ zeiefBuffer = bufferAlloc(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE);
829
+ zeiefBuffer.writeUInt16LE(1, 0);
830
+ zeiefBuffer.writeUInt16LE(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE - 4, 2);
831
+ writeUInt64LE(zeiefBuffer, this.uncompressedSize, 4);
832
+ writeUInt64LE(zeiefBuffer, this.compressedSize, 12);
833
+ writeUInt64LE(zeiefBuffer, this.relativeOffsetOfLocalHeader, 20);
834
+ }
835
+ fixedSizeStuff.writeUInt32LE(33639248, 0);
836
+ fixedSizeStuff.writeUInt16LE(VERSION_MADE_BY, 4);
837
+ fixedSizeStuff.writeUInt16LE(versionNeededToExtract, 6);
838
+ fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 8);
839
+ fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 10);
840
+ fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 12);
841
+ fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 14);
842
+ fixedSizeStuff.writeUInt32LE(this.crc32, 16);
843
+ fixedSizeStuff.writeUInt32LE(normalCompressedSize, 20);
844
+ fixedSizeStuff.writeUInt32LE(normalUncompressedSize, 24);
845
+ fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 28);
846
+ fixedSizeStuff.writeUInt16LE(izutefBuffer.length + zeiefBuffer.length, 30);
847
+ fixedSizeStuff.writeUInt16LE(this.fileComment.length, 32);
848
+ fixedSizeStuff.writeUInt16LE(0, 34);
849
+ fixedSizeStuff.writeUInt16LE(0, 36);
850
+ fixedSizeStuff.writeUInt32LE(this.externalFileAttributes, 38);
851
+ fixedSizeStuff.writeUInt32LE(normalRelativeOffsetOfLocalHeader, 42);
852
+ return Buffer.concat([
853
+ fixedSizeStuff,
854
+ // file name (variable size)
855
+ this.utf8FileName,
856
+ // extra field (variable size)
857
+ izutefBuffer,
858
+ zeiefBuffer,
859
+ // file comment (variable size)
860
+ this.fileComment
861
+ ]);
862
+ };
863
+ Entry.prototype.getCompressionMethod = function() {
864
+ var NO_COMPRESSION = 0;
865
+ var DEFLATE_COMPRESSION = 8;
866
+ return this.compressionLevel === 0 ? NO_COMPRESSION : DEFLATE_COMPRESSION;
867
+ };
868
+ var minDosDate = new Date(1980, 0, 1);
869
+ var maxDosDate = new Date(2107, 11, 31, 23, 59, 58);
870
+ function dateToDosDateTime(jsDate) {
871
+ if (jsDate < minDosDate) jsDate = minDosDate;
872
+ else if (jsDate > maxDosDate) jsDate = maxDosDate;
873
+ var date = 0;
874
+ date |= jsDate.getDate() & 31;
875
+ date |= (jsDate.getMonth() + 1 & 15) << 5;
876
+ date |= (jsDate.getFullYear() - 1980 & 127) << 9;
877
+ var time = 0;
878
+ time |= Math.floor(jsDate.getSeconds() / 2);
879
+ time |= (jsDate.getMinutes() & 63) << 5;
880
+ time |= (jsDate.getHours() & 31) << 11;
881
+ return { date, time };
882
+ }
883
+ function writeUInt64LE(buffer, n, offset) {
884
+ var high = Math.floor(n / 4294967296);
885
+ var low = n % 4294967296;
886
+ buffer.writeUInt32LE(low, offset);
887
+ buffer.writeUInt32LE(high, offset + 4);
888
+ }
889
+ util.inherits(ByteCounter, Transform);
890
+ function ByteCounter(options) {
891
+ Transform.call(this, options);
892
+ this.byteCount = 0;
893
+ }
894
+ ByteCounter.prototype._transform = function(chunk, encoding, cb) {
895
+ this.byteCount += chunk.length;
896
+ cb(null, chunk);
897
+ };
898
+ util.inherits(Crc32Watcher, Transform);
899
+ function Crc32Watcher(options) {
900
+ Transform.call(this, options);
901
+ this.crc32 = 0;
902
+ }
903
+ Crc32Watcher.prototype._transform = function(chunk, encoding, cb) {
904
+ this.crc32 = crc32.unsigned(chunk, this.crc32);
905
+ cb(null, chunk);
906
+ };
907
+ var cp437 = "\0\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\xB6\xA7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xA2\xA3\xA5\u20A7\u0192\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\u2310\xAC\xBD\xBC\xA1\xAB\xBB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\xDF\u0393\u03C0\u03A3\u03C3\xB5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\xB1\u2265\u2264\u2320\u2321\xF7\u2248\xB0\u2219\xB7\u221A\u207F\xB2\u25A0\xA0";
908
+ if (cp437.length !== 256) throw new Error("assertion failure");
909
+ var reverseCp437 = null;
910
+ function encodeCp437(string) {
911
+ if (/^[\x20-\x7e]*$/.test(string)) {
912
+ return bufferFrom(string, "utf-8");
913
+ }
914
+ if (reverseCp437 == null) {
915
+ reverseCp437 = {};
916
+ for (var i = 0; i < cp437.length; i++) {
917
+ reverseCp437[cp437[i]] = i;
918
+ }
919
+ }
920
+ var result = bufferAlloc(string.length);
921
+ for (var i = 0; i < string.length; i++) {
922
+ var b = reverseCp437[string[i]];
923
+ if (b == null) throw new Error("character not encodable in CP437: " + JSON.stringify(string[i]));
924
+ result[i] = b;
925
+ }
926
+ return result;
927
+ }
928
+ function bufferAlloc(size) {
929
+ bufferAlloc = modern;
930
+ try {
931
+ return bufferAlloc(size);
932
+ } catch (e) {
933
+ bufferAlloc = legacy;
934
+ return bufferAlloc(size);
935
+ }
936
+ function modern(size2) {
937
+ return Buffer.allocUnsafe(size2);
938
+ }
939
+ function legacy(size2) {
940
+ return new Buffer(size2);
941
+ }
942
+ }
943
+ function bufferFrom(something, encoding) {
944
+ bufferFrom = modern;
945
+ try {
946
+ return bufferFrom(something, encoding);
947
+ } catch (e) {
948
+ bufferFrom = legacy;
949
+ return bufferFrom(something, encoding);
950
+ }
951
+ function modern(something2, encoding2) {
952
+ return Buffer.from(something2, encoding2);
953
+ }
954
+ function legacy(something2, encoding2) {
955
+ return new Buffer(something2, encoding2);
956
+ }
957
+ }
958
+ function bufferIncludes(buffer, content) {
959
+ bufferIncludes = modern;
960
+ try {
961
+ return bufferIncludes(buffer, content);
962
+ } catch (e) {
963
+ bufferIncludes = legacy;
964
+ return bufferIncludes(buffer, content);
965
+ }
966
+ function modern(buffer2, content2) {
967
+ return buffer2.includes(content2);
968
+ }
969
+ function legacy(buffer2, content2) {
970
+ for (var i = 0; i <= buffer2.length - content2.length; i++) {
971
+ for (var j = 0; ; j++) {
972
+ if (j === content2.length) return true;
973
+ if (buffer2[i + j] !== content2[j]) break;
974
+ }
975
+ }
976
+ return false;
977
+ }
978
+ }
979
+ }
980
+ });
2
981
 
3
982
  // src/cliResult.ts
4
983
  var ExitCode = {
@@ -1606,6 +2585,11 @@ function createAutoHandler(deps = {}) {
1606
2585
  };
1607
2586
  }
1608
2587
 
2588
+ // src/bdd.ts
2589
+ var import_yazl = __toESM(require_yazl(), 1);
2590
+ import { createWriteStream, mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync2, writeFileSync } from "node:fs";
2591
+ import path6 from "node:path";
2592
+
1609
2593
  // src/forgeClient.ts
1610
2594
  var ForgeClientError = class extends Error {
1611
2595
  code;
@@ -1772,8 +2756,17 @@ function parseArgs2(args) {
1772
2756
  const flags = {};
1773
2757
  const boolFlags = /* @__PURE__ */ new Set();
1774
2758
  const unknownFlags = [];
1775
- const supportedValueFlags = /* @__PURE__ */ new Set(["--id", ...CONFIG_FLAGS2]);
1776
- const supportedBoolFlags = /* @__PURE__ */ new Set(["--json"]);
2759
+ const supportedValueFlags = /* @__PURE__ */ new Set([
2760
+ "--id",
2761
+ "--test-case-key",
2762
+ "--format",
2763
+ "--output-dir",
2764
+ "--input-dir",
2765
+ "--feature-id",
2766
+ "--file",
2767
+ ...CONFIG_FLAGS2
2768
+ ]);
2769
+ const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--zip", "--all"]);
1777
2770
  for (let index = 0; index < args.length; index += 1) {
1778
2771
  const token = args[index];
1779
2772
  if (!token.startsWith("--")) {
@@ -1831,6 +2824,94 @@ function toJsonScenario(scenario) {
1831
2824
  updatedAt: scenario.updatedAt
1832
2825
  };
1833
2826
  }
2827
+ function scenarioToFeatureLines(scenario) {
2828
+ const lines = [];
2829
+ const tagSet = /* @__PURE__ */ new Set();
2830
+ tagSet.add(`@testops-scenario-${sanitizeFileToken(scenario.key ?? scenario.id)}`);
2831
+ for (const tag of scenario.tags) {
2832
+ tagSet.add(tag);
2833
+ }
2834
+ for (const issueKey of scenario.linkedIssueKeys) {
2835
+ tagSet.add(`@${issueKey}`);
2836
+ }
2837
+ if (tagSet.size > 0) {
2838
+ lines.push([...tagSet].join(" "));
2839
+ }
2840
+ lines.push(`Feature: ${scenario.featureName}`);
2841
+ lines.push("");
2842
+ lines.push(`Scenario: ${scenario.name}`);
2843
+ for (const step of scenario.steps) {
2844
+ lines.push(` ${step.keyword} ${step.text}`);
2845
+ }
2846
+ return lines;
2847
+ }
2848
+ function scenarioToExportFileName(scenario) {
2849
+ return `${sanitizeFileToken(scenario.key ?? scenario.id)}.feature`;
2850
+ }
2851
+ var ISSUE_KEY_PATTERN = /^[A-Z][A-Z0-9]+-\d+$/;
2852
+ var SCENARIO_METADATA_PATTERN = /^@testops-scenario-([A-Za-z0-9._-]+)$/i;
2853
+ function parseScenarioFeatureFile(raw, filePath) {
2854
+ let featureName = "";
2855
+ let scenarioName = "";
2856
+ let scenarioCount = 0;
2857
+ const tags = [];
2858
+ const steps = [];
2859
+ let inScenario = false;
2860
+ for (const rawLine of raw.split(/\r?\n/)) {
2861
+ const line = rawLine.trim();
2862
+ if (!line) {
2863
+ continue;
2864
+ }
2865
+ if (line.startsWith("@") && !inScenario && !scenarioName) {
2866
+ tags.push(...line.split(/\s+/).filter(Boolean));
2867
+ continue;
2868
+ }
2869
+ if (line.toLowerCase().startsWith("feature:")) {
2870
+ featureName = line.slice("feature:".length).trim();
2871
+ continue;
2872
+ }
2873
+ const scenarioMatch = line.match(/^Scenario(?: Outline)?:\s*(.+)$/i);
2874
+ if (scenarioMatch) {
2875
+ scenarioCount += 1;
2876
+ if (scenarioCount > 1) {
2877
+ return null;
2878
+ }
2879
+ scenarioName = scenarioMatch[1].trim();
2880
+ inScenario = true;
2881
+ continue;
2882
+ }
2883
+ const stepMatch = line.match(/^(Given|When|Then|And|But)\s+(.+)$/);
2884
+ if (stepMatch) {
2885
+ steps.push({
2886
+ keyword: stepMatch[1],
2887
+ text: stepMatch[2].trim()
2888
+ });
2889
+ continue;
2890
+ }
2891
+ }
2892
+ const scenarioTag = tags.map((tag) => tag.match(SCENARIO_METADATA_PATTERN)).find((match) => Boolean(match));
2893
+ const scenarioKeyFromTag = scenarioTag?.[1]?.trim().toUpperCase() ?? "";
2894
+ const fileKeyMatch = path6.basename(filePath ?? "").match(/^(SC-\d+)\.feature$/i);
2895
+ const scenarioKeyFromFile = fileKeyMatch?.[1]?.trim().toUpperCase() ?? "";
2896
+ const scenarioKey = scenarioKeyFromTag || scenarioKeyFromFile;
2897
+ if (scenarioKeyFromTag && scenarioKeyFromFile && scenarioKeyFromTag !== scenarioKeyFromFile) {
2898
+ return null;
2899
+ }
2900
+ if (!featureName || !scenarioName || !scenarioKey || steps.length === 0 || scenarioCount !== 1) {
2901
+ return null;
2902
+ }
2903
+ const linkedIssueKeys = [...new Set(
2904
+ tags.map((tag) => tag.replace(/^@/, "").trim().toUpperCase()).filter((tag) => ISSUE_KEY_PATTERN.test(tag))
2905
+ )];
2906
+ return {
2907
+ scenarioKey,
2908
+ featureName,
2909
+ scenarioName,
2910
+ tags,
2911
+ linkedIssueKeys,
2912
+ steps
2913
+ };
2914
+ }
1834
2915
  function scenarioToLines(scenario) {
1835
2916
  const lines = [
1836
2917
  `BDD scenario: ${scenario.name}`,
@@ -1847,6 +2928,75 @@ function scenarioToLines(scenario) {
1847
2928
  }
1848
2929
  return lines;
1849
2930
  }
2931
+ function featureToLines(feature) {
2932
+ return [
2933
+ `BDD feature: ${feature.payload.name}`,
2934
+ `Feature id: ${feature.id}`,
2935
+ `Project: ${feature.projectKey}`,
2936
+ `Linked issues: ${feature.linkedIssueKeys.join(", ") || "none"}`,
2937
+ `Created: ${feature.createdAt}`,
2938
+ `Scenarios: ${feature.parsedSummary.scenarios}`,
2939
+ `Steps: ${feature.parsedSummary.steps}`,
2940
+ `Lines: ${feature.parsedSummary.lines}`
2941
+ ];
2942
+ }
2943
+ function slugifyFeatureName(value) {
2944
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "feature";
2945
+ }
2946
+ function sanitizeFileToken(value) {
2947
+ return value.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "feature";
2948
+ }
2949
+ function buildFeatureExportFileName(feature, index) {
2950
+ const slug = slugifyFeatureName(feature.payload.name);
2951
+ const ordinal = String(index + 1).padStart(3, "0");
2952
+ return `${ordinal}-${slug}.feature`;
2953
+ }
2954
+ function toExportManifestItems(features, fileNames) {
2955
+ return features.map((feature, index) => ({
2956
+ id: feature.id,
2957
+ name: feature.payload.name,
2958
+ fileName: fileNames[index],
2959
+ linkedIssueKeys: [...feature.linkedIssueKeys],
2960
+ scenarioCount: feature.parsedSummary.scenarios,
2961
+ stepCount: feature.parsedSummary.steps,
2962
+ createdAt: feature.createdAt
2963
+ }));
2964
+ }
2965
+ function toJsonExportManifestItems(items) {
2966
+ return items.map((item) => ({
2967
+ id: item.id,
2968
+ name: item.name,
2969
+ fileName: item.fileName,
2970
+ linkedIssueKeys: [...item.linkedIssueKeys],
2971
+ scenarioCount: item.scenarioCount,
2972
+ stepCount: item.stepCount,
2973
+ createdAt: item.createdAt
2974
+ }));
2975
+ }
2976
+ async function defaultCreateZipArchive(archivePath, entries) {
2977
+ await new Promise((resolve, reject) => {
2978
+ const zip = new import_yazl.ZipFile();
2979
+ const output = zip.outputStream.pipe(createWriteStream(archivePath));
2980
+ output.on("close", () => resolve());
2981
+ output.on("error", reject);
2982
+ zip.outputStream.on("error", reject);
2983
+ for (const entry of entries) {
2984
+ zip.addBuffer(Buffer.from(entry.content, "utf8"), entry.fileName);
2985
+ }
2986
+ zip.end();
2987
+ });
2988
+ }
2989
+ function automationToLines(payload, scenarioKey) {
2990
+ return [
2991
+ `Triggered scenario automation for ${scenarioKey}`,
2992
+ `Automation id: ${payload.automation.id}`,
2993
+ `Status: ${payload.automation.lastStatus ?? "queued"}`,
2994
+ `Triggered at: ${payload.automation.lastTriggeredAt ?? "unknown"}`,
2995
+ `Response status: ${payload.responseStatus}`,
2996
+ `Feature: ${payload.automation.label}`,
2997
+ `Scenario: ${scenarioKey}`
2998
+ ];
2999
+ }
1850
3000
  function missingProjectResponse() {
1851
3001
  return {
1852
3002
  exitCode: ExitCode.ValidationError,
@@ -1856,10 +3006,16 @@ function missingProjectResponse() {
1856
3006
  function createBddHandler(deps = {}) {
1857
3007
  const cwd = deps.cwd ?? process.cwd();
1858
3008
  const env = deps.env ?? process.env;
3009
+ const mkdir = deps.mkdir ?? ((targetPath, options) => mkdirSync(targetPath, options));
3010
+ const readFile = deps.readFile ?? ((filePath) => readFileSync4(filePath, "utf8"));
3011
+ const readDir = deps.readDir ?? ((dirPath) => readdirSync2(dirPath));
3012
+ const writeFile = deps.writeFile ?? ((filePath, content) => writeFileSync(filePath, content, "utf8"));
3013
+ const createZipArchive = deps.createZipArchive ?? defaultCreateZipArchive;
1859
3014
  return async (request, context) => {
1860
3015
  const [subcommand, ...restArgs] = request.args;
1861
3016
  const parsed = parseArgs2(restArgs);
1862
- const useJson = parsed.boolFlags.has("--json");
3017
+ const requestedFormat = (parsed.flags["--format"] ?? "").trim().toLowerCase();
3018
+ const outputFormat = parsed.boolFlags.has("--json") ? "json" : requestedFormat || "text";
1863
3019
  const config = resolveCliConfig(pickConfigArgs2(parsed), env, cwd);
1864
3020
  const projectKey = config.values.projectKey;
1865
3021
  const issueKey = config.values.issueKey;
@@ -1869,17 +3025,476 @@ function createBddHandler(deps = {}) {
1869
3025
  stderr: [`ERROR: Unknown or invalid flags: ${parsed.unknownFlags.join(", ")}`]
1870
3026
  };
1871
3027
  }
3028
+ if (!["text", "json", "feature"].includes(outputFormat)) {
3029
+ return {
3030
+ exitCode: ExitCode.ValidationError,
3031
+ stderr: ["ERROR: Unsupported --format. Use one of: text, json, feature."]
3032
+ };
3033
+ }
1872
3034
  if (!projectKey) {
1873
3035
  return missingProjectResponse();
1874
3036
  }
1875
- if (subcommand === "scenarios") {
3037
+ if (subcommand === "features") {
1876
3038
  const nested = restArgs[0];
1877
- if (nested !== "show") {
3039
+ if (nested !== "export") {
1878
3040
  return {
1879
3041
  exitCode: ExitCode.UsageError,
1880
- stderr: ["ERROR: Unsupported bdd scenarios subcommand. Use: testops bdd scenarios show --id <SCENARIO_ID>"]
3042
+ stderr: [
3043
+ "ERROR: Unsupported bdd features subcommand. Use: testops bdd features export --output-dir <path> [--feature-id <FEATURE_ID>] [--json]"
3044
+ ]
1881
3045
  };
1882
3046
  }
3047
+ const outputDirFlag = parsed.flags["--output-dir"]?.trim() ?? "";
3048
+ const featureId = parsed.flags["--feature-id"]?.trim() ?? "";
3049
+ const zipRequested = parsed.boolFlags.has("--zip");
3050
+ if (!outputDirFlag) {
3051
+ return {
3052
+ exitCode: ExitCode.ValidationError,
3053
+ stderr: ["ERROR: Missing required --output-dir for testops bdd features export."]
3054
+ };
3055
+ }
3056
+ const outputDir = path6.resolve(cwd, outputDirFlag);
3057
+ try {
3058
+ const result = await context.invokeForgeContract("listBddFeatures", {
3059
+ context: {
3060
+ projectKey,
3061
+ issueKey: issueKey || void 0
3062
+ }
3063
+ });
3064
+ if (!result.ok) {
3065
+ return {
3066
+ exitCode: ExitCode.RemoteError,
3067
+ stderr: [`ERROR: ${result.error.code}: ${result.error.message}`]
3068
+ };
3069
+ }
3070
+ const features = (featureId ? result.data.filter((feature) => feature.id === featureId) : result.data).sort((left, right) => left.payload.name.localeCompare(right.payload.name) || left.createdAt.localeCompare(right.createdAt));
3071
+ if (featureId && features.length === 0) {
3072
+ return {
3073
+ exitCode: ExitCode.RemoteError,
3074
+ stderr: [`ERROR: NOT_FOUND: BDD feature ${featureId} was not found in this project.`]
3075
+ };
3076
+ }
3077
+ if (features.length === 0) {
3078
+ return {
3079
+ exitCode: ExitCode.RemoteError,
3080
+ stderr: ["ERROR: NOT_FOUND: No BDD features were found in this project context."]
3081
+ };
3082
+ }
3083
+ mkdir(outputDir, { recursive: true });
3084
+ const fileNames = features.map((feature, index) => buildFeatureExportFileName(feature, index));
3085
+ const manifestItems = toExportManifestItems(features, fileNames);
3086
+ const exportEntries = features.map((feature, index) => ({
3087
+ fileName: fileNames[index],
3088
+ content: `${feature.payload.gherkin.trimEnd()}
3089
+ `
3090
+ }));
3091
+ for (let index = 0; index < features.length; index += 1) {
3092
+ writeFile(path6.join(outputDir, fileNames[index]), exportEntries[index].content);
3093
+ }
3094
+ const manifest = {
3095
+ action: "bdd-features-export",
3096
+ projectKey,
3097
+ issueKey: issueKey || null,
3098
+ outputDir,
3099
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
3100
+ count: features.length,
3101
+ items: manifestItems
3102
+ };
3103
+ const manifestContent = `${JSON.stringify(manifest, null, 2)}
3104
+ `;
3105
+ writeFile(path6.join(outputDir, "manifest.json"), manifestContent);
3106
+ const archivePath = `${outputDir}.zip`;
3107
+ if (zipRequested) {
3108
+ await createZipArchive(archivePath, [
3109
+ ...exportEntries,
3110
+ { fileName: "manifest.json", content: manifestContent }
3111
+ ]);
3112
+ }
3113
+ if (outputFormat === "json") {
3114
+ return {
3115
+ exitCode: ExitCode.Success,
3116
+ stdout: toJsonLine({
3117
+ action: manifest.action,
3118
+ projectKey: manifest.projectKey,
3119
+ issueKey: manifest.issueKey,
3120
+ outputDir: manifest.outputDir,
3121
+ exportedAt: manifest.exportedAt,
3122
+ count: manifest.count,
3123
+ items: toJsonExportManifestItems(manifestItems),
3124
+ archivePath: zipRequested ? archivePath : null
3125
+ })
3126
+ };
3127
+ }
3128
+ return {
3129
+ exitCode: ExitCode.Success,
3130
+ stdout: [
3131
+ `BDD features exported: ${features.length}`,
3132
+ `Output directory: ${outputDir}`,
3133
+ ...zipRequested ? [`ZIP archive: ${archivePath}`] : [],
3134
+ "Files:",
3135
+ ...manifestItems.flatMap((item) => [
3136
+ `- ${item.fileName}`,
3137
+ ...featureToLines(features.find((feature) => feature.id === item.id))
3138
+ ])
3139
+ ]
3140
+ };
3141
+ } catch (error) {
3142
+ return {
3143
+ exitCode: ExitCode.TransportError,
3144
+ stderr: [`ERROR: ${normalizeError(error)}`]
3145
+ };
3146
+ }
3147
+ }
3148
+ if (subcommand === "scenarios") {
3149
+ const nested = restArgs[0];
3150
+ if (nested !== "show") {
3151
+ if (nested !== "run" && nested !== "export" && nested !== "import") {
3152
+ return {
3153
+ exitCode: ExitCode.UsageError,
3154
+ stderr: [
3155
+ "ERROR: Unsupported bdd scenarios subcommand. Use: testops bdd scenarios show|run|export|import ..."
3156
+ ]
3157
+ };
3158
+ }
3159
+ if (nested === "export") {
3160
+ const scenarioSelector = parsed.flags["--id"]?.trim() ?? "";
3161
+ const exportAll = parsed.boolFlags.has("--all");
3162
+ const outputDirFlag = parsed.flags["--output-dir"]?.trim() ?? "";
3163
+ if (!scenarioSelector && !exportAll) {
3164
+ return {
3165
+ exitCode: ExitCode.ValidationError,
3166
+ stderr: ["ERROR: Provide --id <SCENARIO_ID|SC-4> or --all for testops bdd scenarios export."]
3167
+ };
3168
+ }
3169
+ if (!outputDirFlag) {
3170
+ return {
3171
+ exitCode: ExitCode.ValidationError,
3172
+ stderr: ["ERROR: Missing required --output-dir for testops bdd scenarios export."]
3173
+ };
3174
+ }
3175
+ const outputDir = path6.resolve(cwd, outputDirFlag);
3176
+ const zipRequested = parsed.boolFlags.has("--zip");
3177
+ try {
3178
+ const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
3179
+ context: {
3180
+ projectKey,
3181
+ issueKey: issueKey || void 0
3182
+ }
3183
+ });
3184
+ if (!scenariosResult.ok) {
3185
+ return {
3186
+ exitCode: ExitCode.RemoteError,
3187
+ stderr: [`ERROR: ${scenariosResult.error.code}: ${scenariosResult.error.message}`]
3188
+ };
3189
+ }
3190
+ const selectedScenarios = exportAll ? [...scenariosResult.data].sort((left, right) => (left.key ?? left.id).localeCompare(right.key ?? right.id)) : scenariosResult.data.filter(
3191
+ (item) => item.id === scenarioSelector || (item.key ?? "").toUpperCase() === scenarioSelector.toUpperCase()
3192
+ );
3193
+ if (!exportAll && selectedScenarios.length === 0) {
3194
+ return {
3195
+ exitCode: ExitCode.RemoteError,
3196
+ stderr: [`ERROR: NOT_FOUND: BDD scenario ${scenarioSelector} was not found in this project.`]
3197
+ };
3198
+ }
3199
+ if (selectedScenarios.length === 0) {
3200
+ return {
3201
+ exitCode: ExitCode.RemoteError,
3202
+ stderr: ["ERROR: NOT_FOUND: No BDD scenarios were found in this project context."]
3203
+ };
3204
+ }
3205
+ mkdir(outputDir, { recursive: true });
3206
+ const items = selectedScenarios.map((scenario) => {
3207
+ const fileName = scenarioToExportFileName(scenario);
3208
+ const fileContent = `${scenarioToFeatureLines(scenario).join("\n")}
3209
+ `;
3210
+ writeFile(path6.join(outputDir, fileName), fileContent);
3211
+ return {
3212
+ scenario,
3213
+ fileName,
3214
+ fileContent
3215
+ };
3216
+ });
3217
+ const manifest = {
3218
+ action: "bdd-scenarios-export",
3219
+ projectKey,
3220
+ issueKey: issueKey || null,
3221
+ outputDir,
3222
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
3223
+ count: items.length,
3224
+ items: items.map(({ scenario, fileName }) => ({
3225
+ id: scenario.id,
3226
+ key: scenario.key ?? null,
3227
+ featureName: scenario.featureName,
3228
+ scenarioName: scenario.name,
3229
+ fileName,
3230
+ linkedIssueKeys: [...scenario.linkedIssueKeys],
3231
+ tags: [...scenario.tags]
3232
+ }))
3233
+ };
3234
+ const manifestContent = `${JSON.stringify(manifest, null, 2)}
3235
+ `;
3236
+ writeFile(path6.join(outputDir, "manifest.json"), manifestContent);
3237
+ const archivePath = `${outputDir}.zip`;
3238
+ if (zipRequested) {
3239
+ await createZipArchive(archivePath, [
3240
+ ...items.map(({ fileName, fileContent }) => ({ fileName, content: fileContent })),
3241
+ { fileName: "manifest.json", content: manifestContent }
3242
+ ]);
3243
+ }
3244
+ if (outputFormat === "json") {
3245
+ return {
3246
+ exitCode: ExitCode.Success,
3247
+ stdout: toJsonLine({
3248
+ action: manifest.action,
3249
+ projectKey,
3250
+ issueKey: issueKey || null,
3251
+ outputDir,
3252
+ exportedAt: manifest.exportedAt,
3253
+ count: items.length,
3254
+ archivePath: zipRequested ? archivePath : null,
3255
+ items: items.map(({ scenario, fileName }) => ({
3256
+ id: scenario.id,
3257
+ key: scenario.key ?? null,
3258
+ featureName: scenario.featureName,
3259
+ scenarioName: scenario.name,
3260
+ fileName,
3261
+ linkedIssueKeys: [...scenario.linkedIssueKeys],
3262
+ tags: [...scenario.tags]
3263
+ }))
3264
+ })
3265
+ };
3266
+ }
3267
+ return {
3268
+ exitCode: ExitCode.Success,
3269
+ stdout: [
3270
+ `BDD scenarios exported: ${items.length}`,
3271
+ `Output directory: ${outputDir}`,
3272
+ ...zipRequested ? [`ZIP archive: ${archivePath}`] : [],
3273
+ ...items.flatMap(({ scenario, fileName }) => [`File: ${fileName}`, ...scenarioToLines(scenario)])
3274
+ ]
3275
+ };
3276
+ } catch (error) {
3277
+ return {
3278
+ exitCode: ExitCode.TransportError,
3279
+ stderr: [`ERROR: ${normalizeError(error)}`]
3280
+ };
3281
+ }
3282
+ }
3283
+ if (nested === "import") {
3284
+ const sourceFile = parsed.flags["--file"] ? path6.resolve(cwd, parsed.flags["--file"]) : "";
3285
+ const inputDir = parsed.flags["--input-dir"] ? path6.resolve(cwd, parsed.flags["--input-dir"]) : "";
3286
+ if (!sourceFile && !inputDir) {
3287
+ return {
3288
+ exitCode: ExitCode.ValidationError,
3289
+ stderr: ["ERROR: Provide --file <SC-4.feature> or --input-dir <dir> for testops bdd scenarios import."]
3290
+ };
3291
+ }
3292
+ try {
3293
+ const scenarioFiles = sourceFile ? [sourceFile] : readDir(inputDir).filter((entry) => entry.toLowerCase().endsWith(".feature")).map((entry) => path6.join(inputDir, entry)).sort((left, right) => left.localeCompare(right));
3294
+ if (scenarioFiles.length === 0) {
3295
+ return {
3296
+ exitCode: ExitCode.ValidationError,
3297
+ stderr: ["ERROR: No .feature files were found for scenario import."]
3298
+ };
3299
+ }
3300
+ const parsedScenarios = scenarioFiles.map((filePath) => ({
3301
+ filePath,
3302
+ parsed: parseScenarioFeatureFile(readFile(filePath), filePath)
3303
+ }));
3304
+ const invalidScenarioFile = parsedScenarios.find((item) => !item.parsed);
3305
+ if (invalidScenarioFile) {
3306
+ return {
3307
+ exitCode: ExitCode.ValidationError,
3308
+ stderr: [
3309
+ `ERROR: Scenario feature file ${invalidScenarioFile.filePath} must contain exactly one scenario, valid steps, and a matching SC-* key in tag or filename.`
3310
+ ]
3311
+ };
3312
+ }
3313
+ const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
3314
+ context: {
3315
+ projectKey,
3316
+ issueKey: issueKey || void 0
3317
+ }
3318
+ });
3319
+ if (!scenariosResult.ok) {
3320
+ return {
3321
+ exitCode: ExitCode.RemoteError,
3322
+ stderr: [`ERROR: ${scenariosResult.error.code}: ${scenariosResult.error.message}`]
3323
+ };
3324
+ }
3325
+ const updatedItems = [];
3326
+ for (const entry of parsedScenarios) {
3327
+ const parsedScenario = entry.parsed;
3328
+ const scenario = scenariosResult.data.find(
3329
+ (item) => (item.key ?? "").toUpperCase() === parsedScenario.scenarioKey.toUpperCase()
3330
+ );
3331
+ if (!scenario) {
3332
+ return {
3333
+ exitCode: ExitCode.RemoteError,
3334
+ stderr: [`ERROR: NOT_FOUND: BDD scenario ${parsedScenario.scenarioKey} was not found in this project.`]
3335
+ };
3336
+ }
3337
+ const nextTags = parsedScenario.tags.filter((tag) => !SCENARIO_METADATA_PATTERN.test(tag));
3338
+ const updateResult = await context.invokeForgeContract("updateScenario", {
3339
+ context: {
3340
+ projectKey,
3341
+ issueKey: issueKey || void 0
3342
+ },
3343
+ scenarioId: scenario.id,
3344
+ input: {
3345
+ featureName: parsedScenario.featureName,
3346
+ name: parsedScenario.scenarioName,
3347
+ steps: [...parsedScenario.steps],
3348
+ tags: nextTags,
3349
+ linkedIssueKeys: [...parsedScenario.linkedIssueKeys]
3350
+ }
3351
+ });
3352
+ if (!updateResult.ok) {
3353
+ return {
3354
+ exitCode: ExitCode.RemoteError,
3355
+ stderr: [`ERROR: ${updateResult.error.code}: ${updateResult.error.message}`]
3356
+ };
3357
+ }
3358
+ updatedItems.push({
3359
+ file: entry.filePath,
3360
+ item: updateResult.data
3361
+ });
3362
+ }
3363
+ if (outputFormat === "json") {
3364
+ return {
3365
+ exitCode: ExitCode.Success,
3366
+ stdout: toJsonLine({
3367
+ action: "bdd-scenarios-import",
3368
+ projectKey,
3369
+ issueKey: issueKey || null,
3370
+ count: updatedItems.length,
3371
+ file: sourceFile || null,
3372
+ inputDir: inputDir || null,
3373
+ items: updatedItems.map((entry) => ({
3374
+ file: entry.file,
3375
+ item: toJsonScenario(entry.item)
3376
+ }))
3377
+ })
3378
+ };
3379
+ }
3380
+ return {
3381
+ exitCode: ExitCode.Success,
3382
+ stdout: updatedItems.flatMap((entry) => [
3383
+ `BDD scenario imported: ${entry.item.key ?? entry.item.id}`,
3384
+ `Source: ${entry.file}`,
3385
+ ...scenarioToLines(entry.item)
3386
+ ])
3387
+ };
3388
+ } catch (error) {
3389
+ return {
3390
+ exitCode: ExitCode.TransportError,
3391
+ stderr: [`ERROR: ${normalizeError(error)}`]
3392
+ };
3393
+ }
3394
+ }
3395
+ const scenarioId2 = parsed.flags["--id"]?.trim() ?? "";
3396
+ const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
3397
+ if (!scenarioId2 && !testCaseKey) {
3398
+ return {
3399
+ exitCode: ExitCode.ValidationError,
3400
+ stderr: ["ERROR: Provide either --id <SCENARIO_ID> or --test-case-key <TC-197> for testops bdd scenarios run."]
3401
+ };
3402
+ }
3403
+ try {
3404
+ let scenarioIds = [];
3405
+ let scenarioLabel = scenarioId2 || testCaseKey;
3406
+ if (testCaseKey && !scenarioId2) {
3407
+ const testCaseResult = await context.invokeForgeContract("getTestCase", {
3408
+ context: {
3409
+ projectKey,
3410
+ issueKey: issueKey || void 0
3411
+ },
3412
+ testCaseKey
3413
+ });
3414
+ if (!testCaseResult.ok) {
3415
+ return {
3416
+ exitCode: ExitCode.RemoteError,
3417
+ stderr: [`ERROR: ${testCaseResult.error.code}: ${testCaseResult.error.message}`]
3418
+ };
3419
+ }
3420
+ const linksResult = await context.invokeForgeContract("listTestCaseScenarioLinks", {
3421
+ context: {
3422
+ projectKey,
3423
+ issueKey: issueKey || void 0
3424
+ }
3425
+ });
3426
+ if (!linksResult.ok) {
3427
+ return {
3428
+ exitCode: ExitCode.RemoteError,
3429
+ stderr: [`ERROR: ${linksResult.error.code}: ${linksResult.error.message}`]
3430
+ };
3431
+ }
3432
+ const testCase = testCaseResult.data;
3433
+ scenarioIds = linksResult.data.filter((link) => link.testCaseId === testCase.id).map((link) => link.scenarioId);
3434
+ if (scenarioIds.length === 0) {
3435
+ return {
3436
+ exitCode: ExitCode.RemoteError,
3437
+ stderr: [`ERROR: No linked scenarios were found for test case ${testCase.key}.`]
3438
+ };
3439
+ }
3440
+ scenarioLabel = `${testCase.key} (${scenarioIds.length} scenario${scenarioIds.length === 1 ? "" : "s"})`;
3441
+ } else if (scenarioId2) {
3442
+ scenarioIds = [scenarioId2];
3443
+ }
3444
+ const runs = [];
3445
+ for (const currentScenarioId of scenarioIds) {
3446
+ const result = await context.invokeForgeContract("runScenarioAutomation", {
3447
+ context: {
3448
+ projectKey,
3449
+ issueKey: issueKey || void 0
3450
+ },
3451
+ scenarioId: currentScenarioId
3452
+ });
3453
+ if (!result.ok) {
3454
+ return {
3455
+ exitCode: ExitCode.RemoteError,
3456
+ stderr: [`ERROR: ${result.error.code}: ${result.error.message}`]
3457
+ };
3458
+ }
3459
+ runs.push(result.data);
3460
+ }
3461
+ if (outputFormat === "json") {
3462
+ return {
3463
+ exitCode: ExitCode.Success,
3464
+ stdout: toJsonLine({
3465
+ action: "bdd-scenarios-run",
3466
+ projectKey,
3467
+ issueKey: issueKey || null,
3468
+ item: {
3469
+ scenarioLabel,
3470
+ runCount: runs.length,
3471
+ runs: runs.map((run) => ({
3472
+ automationId: run.automation.id,
3473
+ label: run.automation.label,
3474
+ status: run.automation.lastStatus ?? "queued",
3475
+ externalRunId: run.automation.externalRunId ?? null,
3476
+ externalRunUrl: run.automation.externalRunUrl ?? null,
3477
+ responseStatus: run.responseStatus
3478
+ }))
3479
+ }
3480
+ })
3481
+ };
3482
+ }
3483
+ return {
3484
+ exitCode: ExitCode.Success,
3485
+ stdout: [
3486
+ `Scenario automation dispatches: ${runs.length}`,
3487
+ `Target: ${scenarioLabel}`,
3488
+ ...runs.flatMap((run) => automationToLines(run, scenarioLabel))
3489
+ ]
3490
+ };
3491
+ } catch (error) {
3492
+ return {
3493
+ exitCode: ExitCode.TransportError,
3494
+ stderr: [`ERROR: ${normalizeError(error)}`]
3495
+ };
3496
+ }
3497
+ }
1883
3498
  const scenarioId = parsed.flags["--id"]?.trim() ?? "";
1884
3499
  if (!scenarioId) {
1885
3500
  return {
@@ -1901,7 +3516,7 @@ function createBddHandler(deps = {}) {
1901
3516
  stderr: [`ERROR: ${result.error.code}: ${result.error.message}`]
1902
3517
  };
1903
3518
  }
1904
- if (useJson) {
3519
+ if (outputFormat === "json") {
1905
3520
  return {
1906
3521
  exitCode: ExitCode.Success,
1907
3522
  stdout: toJsonLine({
@@ -1912,6 +3527,12 @@ function createBddHandler(deps = {}) {
1912
3527
  })
1913
3528
  };
1914
3529
  }
3530
+ if (outputFormat === "feature") {
3531
+ return {
3532
+ exitCode: ExitCode.Success,
3533
+ stdout: scenarioToFeatureLines(result.data)
3534
+ };
3535
+ }
1915
3536
  return {
1916
3537
  exitCode: ExitCode.Success,
1917
3538
  stdout: scenarioToLines(result.data)
@@ -2556,8 +4177,8 @@ function createDoctorHandler(deps = {}) {
2556
4177
  }
2557
4178
 
2558
4179
  // src/ingestFeature.ts
2559
- import { readFileSync as readFileSync4 } from "node:fs";
2560
- import path6 from "node:path";
4180
+ import { readFileSync as readFileSync5 } from "node:fs";
4181
+ import path7 from "node:path";
2561
4182
  var CONFIG_FLAGS5 = /* @__PURE__ */ new Set([
2562
4183
  "--config",
2563
4184
  "--base-url",
@@ -2643,8 +4264,8 @@ function normalizeError3(error) {
2643
4264
  return "Unknown ingest error.";
2644
4265
  }
2645
4266
  function createIngestFeatureHandler(deps = {}) {
2646
- const readFile = deps.readFile ?? ((filePath) => readFileSync4(filePath, "utf8"));
2647
- const readStdin = deps.readStdin ?? (() => readFileSync4(0, "utf8"));
4267
+ const readFile = deps.readFile ?? ((filePath) => readFileSync5(filePath, "utf8"));
4268
+ const readStdin = deps.readStdin ?? (() => readFileSync5(0, "utf8"));
2648
4269
  const cwd = deps.cwd ?? process.cwd();
2649
4270
  const env = deps.env ?? process.env;
2650
4271
  return async (request, context) => {
@@ -2654,7 +4275,7 @@ function createIngestFeatureHandler(deps = {}) {
2654
4275
  const config = resolveCliConfig(configArgs, env, cwd);
2655
4276
  const projectKey = config.values.projectKey;
2656
4277
  const issueKey = config.values.issueKey;
2657
- const sourceFile = parsed.flags["--file"] ? path6.resolve(cwd, parsed.flags["--file"]) : "";
4278
+ const sourceFile = parsed.flags["--file"] ? path7.resolve(cwd, parsed.flags["--file"]) : "";
2658
4279
  const useStdin = parsed.boolFlags.has("--stdin");
2659
4280
  const useJson = parsed.boolFlags.has("--json");
2660
4281
  const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
@@ -2783,8 +4404,8 @@ function createIngestFeatureHandler(deps = {}) {
2783
4404
  }
2784
4405
 
2785
4406
  // src/runUpload.ts
2786
- import { readFileSync as readFileSync5 } from "node:fs";
2787
- import path7 from "node:path";
4407
+ import { readFileSync as readFileSync6 } from "node:fs";
4408
+ import path8 from "node:path";
2788
4409
  var STEP_RESULTS = [
2789
4410
  StepResult.Passed,
2790
4411
  StepResult.Failed,
@@ -2806,6 +4427,8 @@ function parseArgs6(args) {
2806
4427
  const unknownFlags = [];
2807
4428
  const valuedFlags = /* @__PURE__ */ new Set([
2808
4429
  "--file",
4430
+ "--scenario-id",
4431
+ "--test-case-key",
2809
4432
  "--feature-name",
2810
4433
  "--scenario-name",
2811
4434
  "--executed-at",
@@ -2903,7 +4526,9 @@ function mergeMetadataOverrides(input, parsed) {
2903
4526
  featureName: (parsed.flags["--feature-name"] ?? input.featureName ?? "").trim(),
2904
4527
  scenarioName: (parsed.flags["--scenario-name"] ?? input.scenarioName ?? "").trim(),
2905
4528
  executedAt: (parsed.flags["--executed-at"] ?? input.executedAt ?? "").trim(),
2906
- steps: Array.isArray(input.steps) ? input.steps : []
4529
+ scenarioId: (parsed.flags["--scenario-id"] ?? input.scenarioId ?? "").trim() || void 0,
4530
+ steps: Array.isArray(input.steps) ? input.steps : [],
4531
+ testCaseIds: Array.isArray(input.testCaseIds) ? input.testCaseIds : []
2907
4532
  };
2908
4533
  }
2909
4534
  function summarizeRunResult(result) {
@@ -2921,8 +4546,8 @@ function summarizeRunResult(result) {
2921
4546
  return lines;
2922
4547
  }
2923
4548
  function createRunUploadHandler(deps = {}) {
2924
- const readFile = deps.readFile ?? ((filePath) => readFileSync5(filePath, "utf8"));
2925
- const readStdin = deps.readStdin ?? (() => readFileSync5(0, "utf8"));
4549
+ const readFile = deps.readFile ?? ((filePath) => readFileSync6(filePath, "utf8"));
4550
+ const readStdin = deps.readStdin ?? (() => readFileSync6(0, "utf8"));
2926
4551
  const cwd = deps.cwd ?? process.cwd();
2927
4552
  const env = deps.env ?? process.env;
2928
4553
  return async (request, context) => {
@@ -2932,7 +4557,8 @@ function createRunUploadHandler(deps = {}) {
2932
4557
  const config = resolveCliConfig(configArgs, env, cwd);
2933
4558
  const projectKey = config.values.projectKey;
2934
4559
  const issueKey = config.values.issueKey;
2935
- const sourceFile = parsed.flags["--file"] ? path7.resolve(cwd, parsed.flags["--file"]) : "";
4560
+ const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
4561
+ const sourceFile = parsed.flags["--file"] ? path8.resolve(cwd, parsed.flags["--file"]) : "";
2936
4562
  const useStdin = parsed.boolFlags.has("--stdin");
2937
4563
  const useJson = parsed.boolFlags.has("--json");
2938
4564
  const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
@@ -2971,6 +4597,29 @@ function createRunUploadHandler(deps = {}) {
2971
4597
  };
2972
4598
  }
2973
4599
  const runInput = mergeMetadataOverrides(payloadFromSource, parsed);
4600
+ if (testCaseKey) {
4601
+ try {
4602
+ const testCaseResult = await context.invokeForgeContract("getTestCase", {
4603
+ context: {
4604
+ projectKey,
4605
+ issueKey: issueKey || void 0
4606
+ },
4607
+ testCaseKey
4608
+ });
4609
+ if (!testCaseResult.ok) {
4610
+ return {
4611
+ exitCode: ExitCode.RemoteError,
4612
+ stderr: [`ERROR: ${testCaseResult.error.code}: ${testCaseResult.error.message}`]
4613
+ };
4614
+ }
4615
+ runInput.testCaseIds = [.../* @__PURE__ */ new Set([...runInput.testCaseIds ?? [], testCaseResult.data.id])];
4616
+ } catch (error) {
4617
+ return {
4618
+ exitCode: ExitCode.TransportError,
4619
+ stderr: [`ERROR: ${normalizeError4(error)}`]
4620
+ };
4621
+ }
4622
+ }
2974
4623
  const validationErrors = validateRunInput(runInput);
2975
4624
  if (validationErrors.length > 0) {
2976
4625
  return {
@@ -3755,8 +5404,8 @@ var COMMAND_REGISTRY = [
3755
5404
  },
3756
5405
  {
3757
5406
  name: "bdd",
3758
- description: "BDD scenario inspection commands",
3759
- subcommands: ["scenarios"],
5407
+ description: "BDD scenario inspection and feature export commands",
5408
+ subcommands: ["features", "scenarios"],
3760
5409
  handler: createBddHandler()
3761
5410
  },
3762
5411
  {