agentica 0.44.0-dev.20260313 → 0.44.0-dev.20260313-2

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.mjs CHANGED
@@ -2,11 +2,13 @@ import process$1, { stdin, stdout } from 'node:process';
2
2
  import { stripVTControlCharacters } from 'node:util';
3
3
  import * as g from 'node:readline';
4
4
  import g__default from 'node:readline';
5
- import { Writable } from 'node:stream';
5
+ import { Writable, Readable } from 'node:stream';
6
6
  import { createRequire } from 'node:module';
7
- import fss, { existsSync } from 'node:fs';
8
- import fs, { rm, appendFile, readFile, writeFile } from 'node:fs/promises';
9
- import path, { join } from 'node:path';
7
+ import fss, { createWriteStream, existsSync } from 'node:fs';
8
+ import * as fs from 'node:fs/promises';
9
+ import fs__default, { rm, appendFile, readFile, writeFile } from 'node:fs/promises';
10
+ import * as path from 'node:path';
11
+ import path__default, { join } from 'node:path';
10
12
  import { fileURLToPath } from 'node:url';
11
13
  import { spawn as spawn$1 } from 'node:child_process';
12
14
  import { once, on } from 'node:events';
@@ -16,7 +18,6 @@ import detectIndent from 'detect-indent';
16
18
  import indentString from 'indent-string';
17
19
  import os from 'node:os';
18
20
  import { createGunzip } from 'node:zlib';
19
- import { unpackTar } from 'modern-tar/fs';
20
21
 
21
22
  function getDefaultExportFromCjs (x) {
22
23
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -4560,7 +4561,7 @@ const {
4560
4561
  Help,
4561
4562
  } = commander;
4562
4563
 
4563
- const version = "0.44.0-dev.20260313";
4564
+ const version = "0.44.0-dev.20260313-2";
4564
4565
 
4565
4566
  /**
4566
4567
  * Error thrown when type assertion fails.
@@ -4685,7 +4686,7 @@ const getOptions = ({
4685
4686
  cwd: cwdOption = '.',
4686
4687
  ...options
4687
4688
  }) => {
4688
- const cwd = cwdOption instanceof URL ? fileURLToPath(cwdOption) : path.resolve(cwdOption);
4689
+ const cwd = cwdOption instanceof URL ? fileURLToPath(cwdOption) : path__default.resolve(cwdOption);
4689
4690
  const env = envOption ? {...process$1.env, ...envOption} : undefined;
4690
4691
  const input = stdio[0]?.string;
4691
4692
  return {
@@ -4698,16 +4699,16 @@ const getOptions = ({
4698
4699
  };
4699
4700
 
4700
4701
  const addLocalPath = ({Path = '', PATH = Path, ...env}, cwd) => {
4701
- const pathParts = PATH.split(path.delimiter);
4702
- const localPaths = getLocalPaths([], path.resolve(cwd))
4703
- .map(localPath => path.join(localPath, 'node_modules/.bin'))
4702
+ const pathParts = PATH.split(path__default.delimiter);
4703
+ const localPaths = getLocalPaths([], path__default.resolve(cwd))
4704
+ .map(localPath => path__default.join(localPath, 'node_modules/.bin'))
4704
4705
  .filter(localPath => !pathParts.includes(localPath));
4705
- return {...env, PATH: [...localPaths, PATH].filter(Boolean).join(path.delimiter)};
4706
+ return {...env, PATH: [...localPaths, PATH].filter(Boolean).join(path__default.delimiter)};
4706
4707
  };
4707
4708
 
4708
4709
  const getLocalPaths = (localPaths, localPath) => localPaths.at(-1) === localPath
4709
4710
  ? localPaths
4710
- : getLocalPaths([...localPaths, localPath], path.resolve(localPath, '..'));
4711
+ : getLocalPaths([...localPaths, localPath], path__default.resolve(localPath, '..'));
4711
4712
 
4712
4713
  // When setting `shell: true` under-the-hood, we must manually escape the file and arguments.
4713
4714
  // This ensures arguments are properly split, and prevents command injection.
@@ -4741,11 +4742,11 @@ const memoize = function_ => (...arguments_) =>
4741
4742
  // Use returned assignment to keep code small
4742
4743
  EXE_MEMO[arguments_.join('\0')] ??= function_(...arguments_);
4743
4744
 
4744
- const access = memoize(fs.access);
4745
+ const access = memoize(fs__default.access);
4745
4746
  const mIsExe = memoize(async (file, cwd, PATH) => {
4746
4747
  const parts = PATH
4747
4748
  // `PATH` is ;-separated on Windows
4748
- .split(path.delimiter)
4749
+ .split(path__default.delimiter)
4749
4750
  // `PATH` allows leading/trailing ; on Windows
4750
4751
  .filter(Boolean)
4751
4752
  // `PATH` parts can be double quoted on Windows
@@ -4755,7 +4756,7 @@ const mIsExe = memoize(async (file, cwd, PATH) => {
4755
4756
  try {
4756
4757
  await Promise.any(
4757
4758
  [cwd, ...parts].flatMap(part => exeExtensions
4758
- .map(extension => access(`${path.resolve(part, file)}${extension}`)),
4759
+ .map(extension => access(`${path__default.resolve(part, file)}${extension}`)),
4759
4760
  ),
4760
4761
  );
4761
4762
  } catch {
@@ -5161,6 +5162,598 @@ function insertCodeIntoAgenticaStarter({ content, importCode, connectorCode }) {
5161
5162
  return insertWithIndent(result, "/// INSERT CONTROLLER HERE", connectorCode);
5162
5163
  }
5163
5164
 
5165
+ //#region src/web/compression.ts
5166
+
5167
+ //#endregion
5168
+ //#region src/web/options.ts
5169
+ function createTarOptionsTransformer(options = {}) {
5170
+ return new TransformStream({ async transform(entry, controller) {
5171
+ let header = entry.header;
5172
+ const stripCount = options.strip;
5173
+ if (stripCount && stripCount > 0) {
5174
+ const newName = stripPathComponents(header.name, stripCount);
5175
+ if (newName === null) {
5176
+ drainStream(entry.body);
5177
+ return;
5178
+ }
5179
+ let newLinkname = header.linkname;
5180
+ if (newLinkname?.startsWith("/")) {
5181
+ const strippedLinkTarget = stripPathComponents(newLinkname, stripCount);
5182
+ newLinkname = strippedLinkTarget === null ? "/" : `/${strippedLinkTarget}`;
5183
+ }
5184
+ header = {
5185
+ ...header,
5186
+ name: header.type === "directory" && !newName.endsWith("/") ? `${newName}/` : newName,
5187
+ linkname: newLinkname
5188
+ };
5189
+ }
5190
+ if (options.filter && options.filter(header) === false) {
5191
+ drainStream(entry.body);
5192
+ return;
5193
+ }
5194
+ if (options.map) header = options.map(header);
5195
+ controller.enqueue({
5196
+ header,
5197
+ body: entry.body
5198
+ });
5199
+ } });
5200
+ }
5201
+ function stripPathComponents(path, stripCount) {
5202
+ const components = path.split("/").filter((c) => c.length > 0);
5203
+ if (stripCount >= components.length) return null;
5204
+ return components.slice(stripCount).join("/");
5205
+ }
5206
+ function drainStream(stream) {
5207
+ (async () => {
5208
+ const reader = stream.getReader();
5209
+ try {
5210
+ while (true) {
5211
+ const { done } = await reader.read();
5212
+ if (done) break;
5213
+ }
5214
+ } catch (error) {
5215
+ console.debug("Stream drain error (non-critical):", error);
5216
+ } finally {
5217
+ reader.releaseLock();
5218
+ }
5219
+ })();
5220
+ }
5221
+
5222
+ //#endregion
5223
+ //#region src/web/constants.ts
5224
+ const BLOCK_SIZE = 512;
5225
+ const BLOCK_SIZE_MASK = 511;
5226
+ const USTAR_NAME_OFFSET = 0;
5227
+ const USTAR_NAME_SIZE = 100;
5228
+ const USTAR_MODE_OFFSET = 100;
5229
+ const USTAR_MODE_SIZE = 8;
5230
+ const USTAR_UID_OFFSET = 108;
5231
+ const USTAR_UID_SIZE = 8;
5232
+ const USTAR_GID_OFFSET = 116;
5233
+ const USTAR_GID_SIZE = 8;
5234
+ const USTAR_SIZE_OFFSET = 124;
5235
+ const USTAR_SIZE_SIZE = 12;
5236
+ const USTAR_MTIME_OFFSET = 136;
5237
+ const USTAR_MTIME_SIZE = 12;
5238
+ const USTAR_CHECKSUM_OFFSET = 148;
5239
+ const USTAR_CHECKSUM_SIZE = 8;
5240
+ const USTAR_TYPEFLAG_OFFSET = 156;
5241
+ const USTAR_TYPEFLAG_SIZE = 1;
5242
+ const USTAR_LINKNAME_OFFSET = 157;
5243
+ const USTAR_LINKNAME_SIZE = 100;
5244
+ const USTAR_MAGIC_OFFSET = 257;
5245
+ const USTAR_MAGIC_SIZE = 6;
5246
+ const USTAR_UNAME_OFFSET = 265;
5247
+ const USTAR_UNAME_SIZE = 32;
5248
+ const USTAR_GNAME_OFFSET = 297;
5249
+ const USTAR_GNAME_SIZE = 32;
5250
+ const USTAR_PREFIX_OFFSET = 345;
5251
+ const USTAR_PREFIX_SIZE = 155;
5252
+ const FLAGTYPE = {
5253
+ "0": "file",
5254
+ "1": "link",
5255
+ "2": "symlink",
5256
+ "3": "character-device",
5257
+ "4": "block-device",
5258
+ "5": "directory",
5259
+ "6": "fifo",
5260
+ x: "pax-header",
5261
+ g: "pax-global-header",
5262
+ L: "gnu-long-name",
5263
+ K: "gnu-long-link-name"
5264
+ };
5265
+
5266
+ //#endregion
5267
+ //#region src/web/utils.ts
5268
+ new TextEncoder();
5269
+ const decoder = new TextDecoder();
5270
+ function readString(view, offset, size) {
5271
+ const end = view.indexOf(0, offset);
5272
+ const sliceEnd = end === -1 || end > offset + size ? offset + size : end;
5273
+ return decoder.decode(view.subarray(offset, sliceEnd));
5274
+ }
5275
+ function readOctal(view, offset, size) {
5276
+ let value = 0;
5277
+ const end = offset + size;
5278
+ for (let i = offset; i < end; i++) {
5279
+ const charCode = view[i];
5280
+ if (charCode === 0) break;
5281
+ if (charCode === 32) continue;
5282
+ value = (value << 3) + (charCode - 48);
5283
+ }
5284
+ return value;
5285
+ }
5286
+ function readNumeric(view, offset, size) {
5287
+ if (view[offset] & 128) {
5288
+ let result = 0;
5289
+ for (let i = 0; i < size; i++) result = result << 8 | view[offset + i];
5290
+ return result & ~(128 << (size - 1) * 8);
5291
+ }
5292
+ return readOctal(view, offset, size);
5293
+ }
5294
+ async function streamToBuffer(stream) {
5295
+ const chunks = [];
5296
+ const reader = stream.getReader();
5297
+ let totalLength = 0;
5298
+ try {
5299
+ while (true) {
5300
+ const { done, value } = await reader.read();
5301
+ if (done) break;
5302
+ chunks.push(value);
5303
+ totalLength += value.length;
5304
+ }
5305
+ const result = new Uint8Array(totalLength);
5306
+ let offset = 0;
5307
+ for (const chunk of chunks) {
5308
+ result.set(chunk, offset);
5309
+ offset += chunk.length;
5310
+ }
5311
+ return result;
5312
+ } finally {
5313
+ reader.releaseLock();
5314
+ }
5315
+ }
5316
+
5317
+ //#endregion
5318
+ //#region src/web/checksum.ts
5319
+ const CHECKSUM_SPACE = 32;
5320
+ function validateChecksum(block) {
5321
+ const stored = readOctal(block, USTAR_CHECKSUM_OFFSET, USTAR_CHECKSUM_SIZE);
5322
+ let sum = 0;
5323
+ for (let i = 0; i < block.length; i++) if (i >= USTAR_CHECKSUM_OFFSET && i < USTAR_CHECKSUM_OFFSET + USTAR_CHECKSUM_SIZE) sum += CHECKSUM_SPACE;
5324
+ else sum += block[i];
5325
+ return stored === sum;
5326
+ }
5327
+
5328
+ //#endregion
5329
+ //#region src/web/unpack.ts
5330
+ function createTarDecoder(options = {}) {
5331
+ const strict = options.strict ?? false;
5332
+ const chunks = [];
5333
+ let totalLength = 0;
5334
+ let offset = 0;
5335
+ let currentEntry = null;
5336
+ let paxGlobals = {};
5337
+ let nextEntryOverrides = {};
5338
+ function consume(size) {
5339
+ if (totalLength < size || chunks.length === 0) return null;
5340
+ totalLength -= size;
5341
+ const firstChunk = chunks[0];
5342
+ if (firstChunk.length - offset >= size) {
5343
+ const data$1 = firstChunk.slice(offset, offset + size);
5344
+ offset += size;
5345
+ if (offset === firstChunk.length) {
5346
+ chunks.shift();
5347
+ offset = 0;
5348
+ }
5349
+ return data$1;
5350
+ }
5351
+ const data = new Uint8Array(size);
5352
+ let bytesCopied = 0;
5353
+ while (bytesCopied < size) {
5354
+ const chunk = chunks[0];
5355
+ const bytesToCopy = Math.min(size - bytesCopied, chunk.length - offset);
5356
+ data.set(chunk.subarray(offset, offset + bytesToCopy), bytesCopied);
5357
+ bytesCopied += bytesToCopy;
5358
+ offset += bytesToCopy;
5359
+ if (offset === chunk.length) {
5360
+ chunks.shift();
5361
+ offset = 0;
5362
+ }
5363
+ }
5364
+ return data;
5365
+ }
5366
+ function forward(size, targetController) {
5367
+ const bytesToForward = Math.min(size, totalLength);
5368
+ let forwarded = 0;
5369
+ while (forwarded < bytesToForward && chunks.length > 0) {
5370
+ const firstChunk = chunks[0];
5371
+ const availableInChunk = firstChunk.length - offset;
5372
+ const bytesToSend = Math.min(bytesToForward - forwarded, availableInChunk);
5373
+ targetController.enqueue(firstChunk.subarray(offset, offset + bytesToSend));
5374
+ forwarded += bytesToSend;
5375
+ offset += bytesToSend;
5376
+ if (offset === firstChunk.length) {
5377
+ chunks.shift();
5378
+ offset = 0;
5379
+ }
5380
+ }
5381
+ totalLength -= forwarded;
5382
+ return forwarded;
5383
+ }
5384
+ function unshift(data) {
5385
+ if (offset > 0) {
5386
+ chunks[0] = chunks[0].subarray(offset);
5387
+ offset = 0;
5388
+ }
5389
+ chunks.unshift(data);
5390
+ totalLength += data.length;
5391
+ }
5392
+ return new TransformStream({
5393
+ transform(chunk, controller) {
5394
+ chunks.push(chunk);
5395
+ totalLength += chunk.length;
5396
+ while (true) {
5397
+ if (currentEntry) {
5398
+ const forwarded = forward(currentEntry.bytesLeft, currentEntry.controller);
5399
+ currentEntry.bytesLeft -= forwarded;
5400
+ if (currentEntry.bytesLeft === 0) {
5401
+ const padding = -currentEntry.header.size & BLOCK_SIZE_MASK;
5402
+ if (consume(padding) === null) break;
5403
+ try {
5404
+ currentEntry.controller.close();
5405
+ } catch {}
5406
+ currentEntry = null;
5407
+ } else break;
5408
+ }
5409
+ const headerBlock = consume(BLOCK_SIZE);
5410
+ if (headerBlock === null) break;
5411
+ if (headerBlock.every((b) => b === 0)) {
5412
+ const nextBlock = consume(BLOCK_SIZE);
5413
+ if (nextBlock === null) {
5414
+ unshift(headerBlock);
5415
+ break;
5416
+ }
5417
+ if (nextBlock.every((b) => b === 0)) {
5418
+ controller.terminate();
5419
+ return;
5420
+ } else {
5421
+ unshift(nextBlock);
5422
+ unshift(headerBlock);
5423
+ }
5424
+ }
5425
+ const header = parseUstarHeader(headerBlock, strict);
5426
+ const metaParser = getMetaParser(header.type);
5427
+ if (metaParser) {
5428
+ const dataSize = header.size;
5429
+ const dataBlocksSize = dataSize + BLOCK_SIZE_MASK & -BLOCK_SIZE;
5430
+ if (totalLength < dataBlocksSize) {
5431
+ unshift(headerBlock);
5432
+ break;
5433
+ }
5434
+ const data = consume(dataSize);
5435
+ if (data === null) {
5436
+ unshift(headerBlock);
5437
+ break;
5438
+ }
5439
+ const padding = dataBlocksSize - dataSize;
5440
+ if (padding > 0) {
5441
+ if (consume(padding) === null) {
5442
+ unshift(data);
5443
+ unshift(headerBlock);
5444
+ break;
5445
+ }
5446
+ }
5447
+ const overrides = metaParser(data);
5448
+ if (header.type === "pax-global-header") paxGlobals = Object.assign({}, paxGlobals, overrides);
5449
+ else nextEntryOverrides = Object.assign({}, nextEntryOverrides, overrides);
5450
+ continue;
5451
+ }
5452
+ const finalHeader = header;
5453
+ applyOverrides(finalHeader, paxGlobals);
5454
+ applyOverrides(finalHeader, nextEntryOverrides);
5455
+ if (header.prefix && header.magic === "ustar" && !nextEntryOverrides.name && !paxGlobals.name) finalHeader.name = `${header.prefix}/${finalHeader.name}`;
5456
+ nextEntryOverrides = {};
5457
+ let bodyController;
5458
+ const body = new ReadableStream({ start: (c) => bodyController = c });
5459
+ controller.enqueue({
5460
+ header: finalHeader,
5461
+ body
5462
+ });
5463
+ if (finalHeader.size > 0) currentEntry = {
5464
+ header: finalHeader,
5465
+ bytesLeft: finalHeader.size,
5466
+ controller: bodyController
5467
+ };
5468
+ else try {
5469
+ bodyController.close();
5470
+ } catch {}
5471
+ }
5472
+ },
5473
+ flush(controller) {
5474
+ if (currentEntry) if (strict) {
5475
+ const error = /* @__PURE__ */ new Error(`Tar archive is truncated. Expected ${currentEntry.header.size} bytes but received ${currentEntry.header.size - currentEntry.bytesLeft}.`);
5476
+ currentEntry.controller.error(error);
5477
+ controller.error(error);
5478
+ } else try {
5479
+ currentEntry.controller.close();
5480
+ } catch {}
5481
+ if (strict) {
5482
+ if (chunks.length > 0 && offset < chunks[0].length) {
5483
+ if (chunks[0].subarray(offset).some((b) => b !== 0)) {
5484
+ controller.error(/* @__PURE__ */ new Error("Unexpected data at end of archive."));
5485
+ return;
5486
+ }
5487
+ }
5488
+ for (let i = 1; i < chunks.length; i++) if (chunks[i].some((b) => b !== 0)) {
5489
+ controller.error(/* @__PURE__ */ new Error("Unexpected data at end of archive."));
5490
+ return;
5491
+ }
5492
+ }
5493
+ }
5494
+ });
5495
+ }
5496
+ function parseUstarHeader(block, strict) {
5497
+ if (strict && !validateChecksum(block)) throw new Error("Invalid tar header checksum.");
5498
+ const typeflag = readString(block, USTAR_TYPEFLAG_OFFSET, USTAR_TYPEFLAG_SIZE);
5499
+ const magic = readString(block, USTAR_MAGIC_OFFSET, USTAR_MAGIC_SIZE);
5500
+ if (strict && magic !== "ustar") throw new Error(`Invalid USTAR magic: expected "ustar", got "${magic}"`);
5501
+ return {
5502
+ name: readString(block, USTAR_NAME_OFFSET, USTAR_NAME_SIZE),
5503
+ mode: readOctal(block, USTAR_MODE_OFFSET, USTAR_MODE_SIZE),
5504
+ uid: readNumeric(block, USTAR_UID_OFFSET, USTAR_UID_SIZE),
5505
+ gid: readNumeric(block, USTAR_GID_OFFSET, USTAR_GID_SIZE),
5506
+ size: readNumeric(block, USTAR_SIZE_OFFSET, USTAR_SIZE_SIZE),
5507
+ mtime: /* @__PURE__ */ new Date(readNumeric(block, USTAR_MTIME_OFFSET, USTAR_MTIME_SIZE) * 1e3),
5508
+ checksum: readOctal(block, USTAR_CHECKSUM_OFFSET, USTAR_CHECKSUM_SIZE),
5509
+ type: FLAGTYPE[typeflag] || "file",
5510
+ linkname: readString(block, USTAR_LINKNAME_OFFSET, USTAR_LINKNAME_SIZE),
5511
+ magic,
5512
+ uname: readString(block, USTAR_UNAME_OFFSET, USTAR_UNAME_SIZE),
5513
+ gname: readString(block, USTAR_GNAME_OFFSET, USTAR_GNAME_SIZE),
5514
+ prefix: readString(block, USTAR_PREFIX_OFFSET, USTAR_PREFIX_SIZE)
5515
+ };
5516
+ }
5517
+ function parsePax(buffer) {
5518
+ const overrides = {};
5519
+ const pax = {};
5520
+ let offset = 0;
5521
+ while (offset < buffer.length) {
5522
+ const spaceIndex = buffer.indexOf(32, offset);
5523
+ if (spaceIndex === -1) break;
5524
+ const length = parseInt(decoder.decode(buffer.subarray(offset, spaceIndex)), 10);
5525
+ if (Number.isNaN(length) || length === 0) break;
5526
+ const recordEnd = offset + length;
5527
+ const [key, value] = decoder.decode(buffer.subarray(spaceIndex + 1, recordEnd - 1)).split("=", 2);
5528
+ if (key && value !== void 0) {
5529
+ pax[key] = value;
5530
+ switch (key) {
5531
+ case "path":
5532
+ overrides.name = value;
5533
+ break;
5534
+ case "linkpath":
5535
+ overrides.linkname = value;
5536
+ break;
5537
+ case "size":
5538
+ overrides.size = parseInt(value, 10);
5539
+ break;
5540
+ case "mtime":
5541
+ overrides.mtime = parseFloat(value);
5542
+ break;
5543
+ case "uid":
5544
+ overrides.uid = parseInt(value, 10);
5545
+ break;
5546
+ case "gid":
5547
+ overrides.gid = parseInt(value, 10);
5548
+ break;
5549
+ case "uname":
5550
+ overrides.uname = value;
5551
+ break;
5552
+ case "gname":
5553
+ overrides.gname = value;
5554
+ break;
5555
+ }
5556
+ }
5557
+ offset = recordEnd;
5558
+ }
5559
+ if (Object.keys(pax).length > 0) overrides.pax = pax;
5560
+ return overrides;
5561
+ }
5562
+ function applyOverrides(header, overrides) {
5563
+ if (overrides.name !== void 0) header.name = overrides.name;
5564
+ if (overrides.linkname !== void 0) header.linkname = overrides.linkname;
5565
+ if (overrides.size !== void 0) header.size = overrides.size;
5566
+ if (overrides.mtime !== void 0) header.mtime = /* @__PURE__ */ new Date(overrides.mtime * 1e3);
5567
+ if (overrides.uid !== void 0) header.uid = overrides.uid;
5568
+ if (overrides.gid !== void 0) header.gid = overrides.gid;
5569
+ if (overrides.uname !== void 0) header.uname = overrides.uname;
5570
+ if (overrides.gname !== void 0) header.gname = overrides.gname;
5571
+ if (overrides.pax) header.pax = Object.assign({}, header.pax ?? {}, overrides.pax);
5572
+ }
5573
+ function getMetaParser(type) {
5574
+ switch (type) {
5575
+ case "pax-global-header":
5576
+ case "pax-header": return parsePax;
5577
+ case "gnu-long-name": return (data) => ({ name: readString(data, 0, data.length) });
5578
+ case "gnu-long-link-name": return (data) => ({ linkname: readString(data, 0, data.length) });
5579
+ default: return;
5580
+ }
5581
+ }
5582
+
5583
+ //#endregion
5584
+ //#region src/fs/path.ts
5585
+ const unicodeCache = /* @__PURE__ */ new Map();
5586
+ const MAX_CACHE_SIZE = 1e4;
5587
+ const normalizeUnicode = (s) => {
5588
+ let result = unicodeCache.get(s);
5589
+ if (result !== void 0) unicodeCache.delete(s);
5590
+ result = result ?? s.normalize("NFD");
5591
+ unicodeCache.set(s, result);
5592
+ const overflow = unicodeCache.size - MAX_CACHE_SIZE;
5593
+ if (overflow > MAX_CACHE_SIZE / 10) {
5594
+ const keys = unicodeCache.keys();
5595
+ for (let i = 0; i < overflow; i++) unicodeCache.delete(keys.next().value);
5596
+ }
5597
+ return result;
5598
+ };
5599
+ async function validatePath(currentPath, root, cache) {
5600
+ const normalizedPath = normalizeUnicode(currentPath);
5601
+ if (normalizedPath === root || cache.has(normalizedPath)) return;
5602
+ const relativePath = path.relative(root, normalizedPath);
5603
+ if (!relativePath) return;
5604
+ const components = relativePath.split(path.sep);
5605
+ let current = root;
5606
+ for (const component of components) {
5607
+ current = path.join(current, component);
5608
+ if (cache.has(current)) continue;
5609
+ let stat$1;
5610
+ try {
5611
+ stat$1 = await fs.lstat(current);
5612
+ } catch (err) {
5613
+ if (err instanceof Error && "code" in err && (err.code === "ENOENT" || err.code === "EPERM")) {
5614
+ cache.add(current);
5615
+ continue;
5616
+ }
5617
+ throw err;
5618
+ }
5619
+ if (stat$1.isDirectory()) {
5620
+ cache.add(current);
5621
+ continue;
5622
+ }
5623
+ if (stat$1.isSymbolicLink()) {
5624
+ const realPath = await fs.realpath(current);
5625
+ validateBounds(realPath, root, `Path traversal attempt detected: symlink "${current}" points outside the extraction directory.`);
5626
+ cache.add(current);
5627
+ continue;
5628
+ }
5629
+ throw new Error(`Path traversal attempt detected: "${current}" is not a valid directory component.`);
5630
+ }
5631
+ }
5632
+ function validateBounds(targetPath, destDir, errorMessage) {
5633
+ const normalizedTarget = normalizeUnicode(targetPath);
5634
+ if (!(normalizedTarget === destDir || normalizedTarget.startsWith(destDir + path.sep))) throw new Error(errorMessage);
5635
+ }
5636
+
5637
+ //#endregion
5638
+ //#region src/fs/unpack.ts
5639
+ function unpackTar(directoryPath, options = {}) {
5640
+ const { readable, writable: webWritable } = new TransformStream();
5641
+ const entryStream = readable.pipeThrough(createTarDecoder(options)).pipeThrough(createTarOptionsTransformer(options));
5642
+ const webWriter = webWritable.getWriter();
5643
+ let isWriterClosed = false;
5644
+ let isProcessingComplete = false;
5645
+ const processingPromise = (async () => {
5646
+ const resolvedDestDir = normalizeUnicode(path.resolve(directoryPath));
5647
+ const validatedDirs = new Set([resolvedDestDir]);
5648
+ await fs.mkdir(resolvedDestDir, { recursive: true });
5649
+ const reader = entryStream.getReader();
5650
+ try {
5651
+ const maxDepth = options.maxDepth ?? 1024;
5652
+ while (true) {
5653
+ const { done, value: entry } = await reader.read();
5654
+ if (done) break;
5655
+ const { header } = entry;
5656
+ const normalizedName = normalizeUnicode(header.name);
5657
+ if (maxDepth !== Infinity) {
5658
+ const depth = normalizedName.split("/").length;
5659
+ if (depth > maxDepth) throw new Error(`Path depth of entry "${header.name}" (${depth}) exceeds the maximum allowed depth of ${maxDepth}.`);
5660
+ }
5661
+ if (path.isAbsolute(normalizedName)) throw new Error(`Path traversal attempt detected for entry "${header.name}".`);
5662
+ const outPath = path.join(resolvedDestDir, normalizedName);
5663
+ validateBounds(outPath, resolvedDestDir, `Path traversal attempt detected for entry "${header.name}".`);
5664
+ const parentDir = path.dirname(outPath);
5665
+ await validatePath(parentDir, resolvedDestDir, validatedDirs);
5666
+ await fs.mkdir(parentDir, { recursive: true });
5667
+ switch (header.type) {
5668
+ case "directory": {
5669
+ const mode = options.dmode ?? header.mode;
5670
+ await fs.mkdir(outPath, {
5671
+ recursive: true,
5672
+ mode
5673
+ });
5674
+ validatedDirs.add(outPath);
5675
+ break;
5676
+ }
5677
+ case "file":
5678
+ if (header.size <= 32 * 1024) await fs.writeFile(outPath, await streamToBuffer(entry.body), { mode: options.fmode ?? header.mode });
5679
+ else await pipeline(Readable.fromWeb(entry.body), createWriteStream(outPath, { mode: options.fmode ?? header.mode }));
5680
+ break;
5681
+ case "symlink":
5682
+ if (!header.linkname) break;
5683
+ if (options.validateSymlinks ?? true) {
5684
+ const symlinkDir = path.dirname(outPath);
5685
+ const resolvedTarget = path.resolve(symlinkDir, header.linkname);
5686
+ validateBounds(resolvedTarget, resolvedDestDir, `Symlink target "${header.linkname}" points outside the extraction directory.`);
5687
+ }
5688
+ await fs.symlink(header.linkname, outPath);
5689
+ if (process.platform === "win32") {
5690
+ validatedDirs.clear();
5691
+ validatedDirs.add(resolvedDestDir);
5692
+ } else validatedDirs.delete(outPath);
5693
+ break;
5694
+ case "link": {
5695
+ if (!header.linkname) break;
5696
+ const normalizedLinkname = normalizeUnicode(header.linkname);
5697
+ if (path.isAbsolute(normalizedLinkname)) throw new Error(`Hardlink target "${header.linkname}" points outside the extraction directory.`);
5698
+ const resolvedLinkTarget = path.resolve(resolvedDestDir, normalizedLinkname);
5699
+ validateBounds(resolvedLinkTarget, resolvedDestDir, `Hardlink target "${header.linkname}" points outside the extraction directory.`);
5700
+ await validatePath(path.dirname(resolvedLinkTarget), resolvedDestDir, validatedDirs);
5701
+ await fs.link(resolvedLinkTarget, outPath);
5702
+ break;
5703
+ }
5704
+ default:
5705
+ await entry.body.cancel();
5706
+ break;
5707
+ }
5708
+ if (header.mtime) try {
5709
+ await (header.type === "symlink" ? fs.lutimes : fs.utimes)(outPath, header.mtime, header.mtime);
5710
+ } catch {}
5711
+ }
5712
+ } finally {
5713
+ isProcessingComplete = true;
5714
+ reader.releaseLock();
5715
+ }
5716
+ })().catch((err) => {
5717
+ isProcessingComplete = true;
5718
+ throw err;
5719
+ });
5720
+ return new Writable({
5721
+ async write(chunk, _encoding, callback) {
5722
+ if (isWriterClosed || isProcessingComplete || webWriter.desiredSize === null) return callback();
5723
+ try {
5724
+ await webWriter.write(chunk);
5725
+ callback();
5726
+ } catch (err) {
5727
+ if (err instanceof TypeError && err.stack?.includes("TransformStream") && webWriter.desiredSize === null) return callback();
5728
+ callback(err);
5729
+ }
5730
+ },
5731
+ async final(callback) {
5732
+ if (isWriterClosed) return callback();
5733
+ try {
5734
+ isWriterClosed = true;
5735
+ try {
5736
+ await webWriter.close();
5737
+ } catch {}
5738
+ await processingPromise;
5739
+ callback();
5740
+ } catch (err) {
5741
+ callback(err);
5742
+ }
5743
+ },
5744
+ destroy(err, callback) {
5745
+ if (isWriterClosed) return callback(err);
5746
+ isWriterClosed = true;
5747
+ isProcessingComplete = true;
5748
+ webWriter.abort(err).catch(() => {});
5749
+ entryStream.cancel(err).catch(() => {});
5750
+ processingPromise.finally(() => {
5751
+ callback(err);
5752
+ });
5753
+ }
5754
+ });
5755
+ }
5756
+
5164
5757
  class UnsupportedProviderError extends Error {}
5165
5758
  class DownloadFailedError extends Error {}
5166
5759
  class SubdirNotFoundError extends Error {}
@@ -5174,7 +5767,7 @@ class DirExistError extends Error {}
5174
5767
  /** @type {AsyncTemplateProvider} */
5175
5768
  const http = async (input, options) => {
5176
5769
  const url = new URL(input);
5177
- const name = path.basename(url.pathname);
5770
+ const name = path__default.basename(url.pathname);
5178
5771
  return {
5179
5772
  name,
5180
5773
  version: undefined,
@@ -5350,7 +5943,7 @@ function getProvider(input, providerName, providers$1) {
5350
5943
  async function download(url, filePath, options = {}) {
5351
5944
  const infoPath = filePath + '.json';
5352
5945
  /** @type {{ etag?: string }} */
5353
- const info = JSON.parse(await fs.readFile(infoPath, 'utf8').catch(() => '{}'));
5946
+ const info = JSON.parse(await fs__default.readFile(infoPath, 'utf8').catch(() => '{}'));
5354
5947
  const headResponse = await sendFetch(url, {
5355
5948
  ...options,
5356
5949
  method: 'HEAD',
@@ -5376,11 +5969,11 @@ async function download(url, filePath, options = {}) {
5376
5969
  )
5377
5970
  }
5378
5971
 
5379
- await fs.mkdir(path.dirname(filePath), { recursive: true });
5972
+ await fs__default.mkdir(path__default.dirname(filePath), { recursive: true });
5380
5973
  const stream = fss.createWriteStream(filePath);
5381
5974
  await pipeline(response.body, stream);
5382
5975
 
5383
- await fs.writeFile(infoPath, JSON.stringify(info), 'utf8');
5976
+ await fs__default.writeFile(infoPath, JSON.stringify(info), 'utf8');
5384
5977
  }
5385
5978
 
5386
5979
  const inputRegex =
@@ -5428,8 +6021,8 @@ async function sendFetch(url, options = {}) {
5428
6021
 
5429
6022
  function cacheDirectory() {
5430
6023
  return process.env.XDG_CACHE_HOME
5431
- ? path.resolve(process.env.XDG_CACHE_HOME, 'bluwy-giget')
5432
- : path.resolve(os.homedir(), '.cache/bluwy-giget')
6024
+ ? path__default.resolve(process.env.XDG_CACHE_HOME, 'bluwy-giget')
6025
+ : path__default.resolve(os.homedir(), '.cache/bluwy-giget')
5433
6026
  }
5434
6027
 
5435
6028
  /**
@@ -5454,7 +6047,7 @@ async function extract(tarPath, extractPath, subdir) {
5454
6047
 
5455
6048
  let subdirFound = false;
5456
6049
  // Create an empty directory here to make tar happy
5457
- await fs.mkdir(extractPath, { recursive: true });
6050
+ await fs__default.mkdir(extractPath, { recursive: true });
5458
6051
 
5459
6052
  const readStream = fss.createReadStream(tarPath);
5460
6053
  const unpackStream = unpackTar(extractPath, {
@@ -5493,7 +6086,7 @@ async function extract(tarPath, extractPath, subdir) {
5493
6086
 
5494
6087
  if (subdir && !subdirFound) {
5495
6088
  // Clean up as it should be empty
5496
- await fs.rm(extractPath, { recursive: true, force: true });
6089
+ await fs__default.rm(extractPath, { recursive: true, force: true });
5497
6090
  throw new SubdirNotFoundError(`Subdirectory not found in tar: ${subdir}`)
5498
6091
  }
5499
6092
  }
@@ -5529,12 +6122,12 @@ async function downloadTemplate(input, options = {}) {
5529
6122
  );
5530
6123
 
5531
6124
  // Download template source
5532
- const temporaryDirectory = path.resolve(
6125
+ const temporaryDirectory = path__default.resolve(
5533
6126
  cacheDirectory(),
5534
6127
  providerName,
5535
6128
  template.name,
5536
6129
  );
5537
- const tarPath = path.resolve(
6130
+ const tarPath = path__default.resolve(
5538
6131
  temporaryDirectory,
5539
6132
  (template.version || template.name) + '.tar.gz',
5540
6133
  );
@@ -5561,10 +6154,10 @@ async function downloadTemplate(input, options = {}) {
5561
6154
  }
5562
6155
 
5563
6156
  // Extract template
5564
- const cwd = path.resolve(options.cwd || '.');
5565
- const extractPath = path.resolve(cwd, options.dir || template.defaultDir);
6157
+ const cwd = path__default.resolve(options.cwd || '.');
6158
+ const extractPath = path__default.resolve(cwd, options.dir || template.defaultDir);
5566
6159
  if (options.force === 'clean') {
5567
- await fs.rm(extractPath, { recursive: true, force: true });
6160
+ await fs__default.rm(extractPath, { recursive: true, force: true });
5568
6161
  } else if (
5569
6162
  !options.force &&
5570
6163
  fss.existsSync(extractPath) &&