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 +621 -28
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
9
|
-
import
|
|
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) :
|
|
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(
|
|
4702
|
-
const localPaths = getLocalPaths([],
|
|
4703
|
-
.map(localPath =>
|
|
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(
|
|
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],
|
|
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(
|
|
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(
|
|
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(`${
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
-
?
|
|
5432
|
-
:
|
|
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
|
|
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
|
|
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 =
|
|
6125
|
+
const temporaryDirectory = path__default.resolve(
|
|
5533
6126
|
cacheDirectory(),
|
|
5534
6127
|
providerName,
|
|
5535
6128
|
template.name,
|
|
5536
6129
|
);
|
|
5537
|
-
const tarPath =
|
|
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 =
|
|
5565
|
-
const extractPath =
|
|
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
|
|
6160
|
+
await fs__default.rm(extractPath, { recursive: true, force: true });
|
|
5568
6161
|
} else if (
|
|
5569
6162
|
!options.force &&
|
|
5570
6163
|
fss.existsSync(extractPath) &&
|