@callstack/apex 0.3.2 → 0.4.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/README.md +71 -45
- package/dist/cli.js +884 -601
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -48,13 +48,13 @@ function createScanner(text, ignoreTrivia = false) {
|
|
|
48
48
|
if (text.charCodeAt(pos) === 48) pos++;
|
|
49
49
|
else {
|
|
50
50
|
pos++;
|
|
51
|
-
while (pos < text.length && isDigit(text.charCodeAt(pos))) pos++;
|
|
51
|
+
while (pos < text.length && isDigit$1(text.charCodeAt(pos))) pos++;
|
|
52
52
|
}
|
|
53
53
|
if (pos < text.length && text.charCodeAt(pos) === 46) {
|
|
54
54
|
pos++;
|
|
55
|
-
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
55
|
+
if (pos < text.length && isDigit$1(text.charCodeAt(pos))) {
|
|
56
56
|
pos++;
|
|
57
|
-
while (pos < text.length && isDigit(text.charCodeAt(pos))) pos++;
|
|
57
|
+
while (pos < text.length && isDigit$1(text.charCodeAt(pos))) pos++;
|
|
58
58
|
} else {
|
|
59
59
|
scanError = 3;
|
|
60
60
|
return text.substring(start, pos);
|
|
@@ -64,9 +64,9 @@ function createScanner(text, ignoreTrivia = false) {
|
|
|
64
64
|
if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
|
|
65
65
|
pos++;
|
|
66
66
|
if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) pos++;
|
|
67
|
-
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
67
|
+
if (pos < text.length && isDigit$1(text.charCodeAt(pos))) {
|
|
68
68
|
pos++;
|
|
69
|
-
while (pos < text.length && isDigit(text.charCodeAt(pos))) pos++;
|
|
69
|
+
while (pos < text.length && isDigit$1(text.charCodeAt(pos))) pos++;
|
|
70
70
|
end = pos;
|
|
71
71
|
} else scanError = 3;
|
|
72
72
|
}
|
|
@@ -234,7 +234,7 @@ function createScanner(text, ignoreTrivia = false) {
|
|
|
234
234
|
case 45:
|
|
235
235
|
value += String.fromCharCode(code);
|
|
236
236
|
pos++;
|
|
237
|
-
if (pos === len || !isDigit(text.charCodeAt(pos))) return token = 16;
|
|
237
|
+
if (pos === len || !isDigit$1(text.charCodeAt(pos))) return token = 16;
|
|
238
238
|
case 48:
|
|
239
239
|
case 49:
|
|
240
240
|
case 50:
|
|
@@ -306,7 +306,7 @@ function isWhiteSpace(ch) {
|
|
|
306
306
|
function isLineBreak(ch) {
|
|
307
307
|
return ch === 10 || ch === 13;
|
|
308
308
|
}
|
|
309
|
-
function isDigit(ch) {
|
|
309
|
+
function isDigit$1(ch) {
|
|
310
310
|
return ch >= 48 && ch <= 57;
|
|
311
311
|
}
|
|
312
312
|
var CharacterCodes;
|
|
@@ -1275,11 +1275,11 @@ function applyEdits(text, edits) {
|
|
|
1275
1275
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1276
1276
|
*/
|
|
1277
1277
|
function getLineColFromPtr(string, ptr) {
|
|
1278
|
-
let lines = string.slice(0, ptr).split(/\r
|
|
1278
|
+
let lines = string.slice(0, ptr).split(/\r?\n/);
|
|
1279
1279
|
return [lines.length, lines.pop().length + 1];
|
|
1280
1280
|
}
|
|
1281
1281
|
function makeCodeBlock(string, line, column) {
|
|
1282
|
-
let lines = string.split(/\r
|
|
1282
|
+
let lines = string.split(/\r?\n/);
|
|
1283
1283
|
let codeblock = "";
|
|
1284
1284
|
let numberLen = (Math.log10(line + 1) | 0) + 1;
|
|
1285
1285
|
for (let i = line - 1; i <= line + 1; i++) {
|
|
@@ -1296,7 +1296,7 @@ function makeCodeBlock(string, line, column) {
|
|
|
1296
1296
|
}
|
|
1297
1297
|
return codeblock;
|
|
1298
1298
|
}
|
|
1299
|
-
var TomlError = class extends Error {
|
|
1299
|
+
var TomlError = class TomlError extends Error {
|
|
1300
1300
|
line;
|
|
1301
1301
|
column;
|
|
1302
1302
|
codeblock;
|
|
@@ -1308,10 +1308,17 @@ var TomlError = class extends Error {
|
|
|
1308
1308
|
this.column = column;
|
|
1309
1309
|
this.codeblock = codeblock;
|
|
1310
1310
|
}
|
|
1311
|
+
/** @internal */
|
|
1312
|
+
static x(message, ctx, ptr) {
|
|
1313
|
+
throw new TomlError(message, {
|
|
1314
|
+
toml: ctx.s,
|
|
1315
|
+
ptr: ptr ?? ctx.p
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1311
1318
|
};
|
|
1312
1319
|
|
|
1313
1320
|
//#endregion
|
|
1314
|
-
//#region node_modules/smol-toml/dist/
|
|
1321
|
+
//#region node_modules/smol-toml/dist/primitive.js
|
|
1315
1322
|
/*!
|
|
1316
1323
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
1317
1324
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
@@ -1339,64 +1346,76 @@ var TomlError = class extends Error {
|
|
|
1339
1346
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1340
1347
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1341
1348
|
*/
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
let
|
|
1349
|
-
if (
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
function skipComment(str, ptr) {
|
|
1353
|
-
for (let i = ptr; i < str.length; i++) {
|
|
1354
|
-
let c = str[i];
|
|
1355
|
-
if (c === "\n") return i;
|
|
1356
|
-
if (c === "\r" && str[i + 1] === "\n") return i + 1;
|
|
1357
|
-
if (c < " " && c !== " " || c === "") throw new TomlError("control characters are not allowed in comments", {
|
|
1358
|
-
toml: str,
|
|
1359
|
-
ptr
|
|
1360
|
-
});
|
|
1349
|
+
/** @internal */
|
|
1350
|
+
function parseString(ctx) {
|
|
1351
|
+
let startPtr = ctx.p;
|
|
1352
|
+
let c = ctx.s.charCodeAt(ctx.p++);
|
|
1353
|
+
let first = c;
|
|
1354
|
+
let isLiteral = c === 39;
|
|
1355
|
+
let isMultiline = c === ctx.s.charCodeAt(ctx.p) && c === ctx.s.charCodeAt(ctx.p + 1);
|
|
1356
|
+
if (isMultiline) {
|
|
1357
|
+
if ((c = ctx.s.charCodeAt(ctx.p += 2)) === 10) ctx.p++;
|
|
1358
|
+
else if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) ctx.p += 2;
|
|
1361
1359
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1360
|
+
let parsed = "";
|
|
1361
|
+
let sliceStart = ctx.p;
|
|
1362
|
+
let state = 0;
|
|
1363
|
+
for (; ctx.p < ctx.s.length; ctx.p++) {
|
|
1364
|
+
c = ctx.s.charCodeAt(ctx.p);
|
|
1365
|
+
if (isMultiline && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)) state = state && 3;
|
|
1366
|
+
else if (c < 32 && c !== 9 || c === 127) TomlError.x("control characters are not allowed in strings", ctx);
|
|
1367
|
+
else if ((!state || state === 3) && c === first && (!isMultiline || ctx.s.charCodeAt(ctx.p + 1) === first && ctx.s.charCodeAt(ctx.p + 2) === first)) {
|
|
1368
|
+
if (isMultiline) {
|
|
1369
|
+
if (ctx.s.charCodeAt(ctx.p + 3) === first) ctx.p++;
|
|
1370
|
+
if (ctx.s.charCodeAt(ctx.p + 3) === first) ctx.p++;
|
|
1371
|
+
}
|
|
1372
|
+
if (!state) {
|
|
1373
|
+
let s = ctx.s.slice(sliceStart, ctx.p);
|
|
1374
|
+
parsed = parsed ? parsed + s : s;
|
|
1375
|
+
}
|
|
1376
|
+
ctx.p += isMultiline ? 3 : 1;
|
|
1377
|
+
return parsed;
|
|
1378
|
+
} else if (!state) {
|
|
1379
|
+
if (!isLiteral && c === 92) {
|
|
1380
|
+
parsed += ctx.s.slice(sliceStart, sliceStart = ctx.p);
|
|
1381
|
+
state = 1;
|
|
1382
|
+
}
|
|
1383
|
+
} else if (state === 1) {
|
|
1384
|
+
if (c === 120 || c === 117 || c === 85) {
|
|
1385
|
+
let errPtr = ctx.p++ - 1;
|
|
1386
|
+
let value = 0;
|
|
1387
|
+
let len = c === 120 ? 2 : c === 117 ? 4 : 8;
|
|
1388
|
+
for (let j = 0; j < len; j++, ctx.p++) {
|
|
1389
|
+
let hex = ctx.s.charCodeAt(ctx.p);
|
|
1390
|
+
let digit = hex >= 48 && hex <= 57 ? hex - 48 : hex >= 65 && hex <= 70 ? hex - 65 + 10 : hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1;
|
|
1391
|
+
if (digit < 0) TomlError.x("invalid non-hex character in unicode escape", ctx);
|
|
1392
|
+
value = value << 4 | digit;
|
|
1393
|
+
}
|
|
1394
|
+
if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) TomlError.x("invalid unicode escape", ctx, errPtr);
|
|
1395
|
+
parsed += String.fromCodePoint(value);
|
|
1396
|
+
sliceStart = ctx.p--;
|
|
1397
|
+
state = 0;
|
|
1398
|
+
} else if (isMultiline && (c === 32 || c === 9)) state = 2;
|
|
1399
|
+
else {
|
|
1400
|
+
if (c === 98) parsed += "\b";
|
|
1401
|
+
else if (c === 116) parsed += " ";
|
|
1402
|
+
else if (c === 110) parsed += "\n";
|
|
1403
|
+
else if (c === 102) parsed += "\f";
|
|
1404
|
+
else if (c === 114) parsed += "\r";
|
|
1405
|
+
else if (c === 101) parsed += "\x1B";
|
|
1406
|
+
else if (c === 34) parsed += "\"";
|
|
1407
|
+
else if (c === 92) parsed += "\\";
|
|
1408
|
+
else TomlError.x("unrecognised escape sequence", ctx);
|
|
1409
|
+
sliceStart = ctx.p + 1;
|
|
1410
|
+
state = 0;
|
|
1411
|
+
}
|
|
1412
|
+
} else if (c !== 32 && c !== 9) {
|
|
1413
|
+
if (state === 2) TomlError.x("invalid escape: only line-ending whitespace may be escaped", ctx, sliceStart);
|
|
1414
|
+
state = !isLiteral && c === 92 ? 1 : 0;
|
|
1415
|
+
sliceStart = ctx.p;
|
|
1397
1416
|
}
|
|
1398
1417
|
}
|
|
1399
|
-
|
|
1418
|
+
TomlError.x("unfinished string", ctx, startPtr);
|
|
1400
1419
|
}
|
|
1401
1420
|
|
|
1402
1421
|
//#endregion
|
|
@@ -1428,31 +1447,48 @@ function getStringEnd(str, seek) {
|
|
|
1428
1447
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1429
1448
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1430
1449
|
*/
|
|
1431
|
-
let DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[
|
|
1450
|
+
let DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[Tt ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|z|[-+]\d{2}:\d{2})?$/i;
|
|
1432
1451
|
var TomlDate = class TomlDate extends Date {
|
|
1433
1452
|
#hasDate = false;
|
|
1434
1453
|
#hasTime = false;
|
|
1435
1454
|
#offset = null;
|
|
1436
|
-
constructor(date) {
|
|
1455
|
+
constructor(date, fasttype, unsafeDelim) {
|
|
1437
1456
|
let hasDate = true;
|
|
1438
1457
|
let hasTime = true;
|
|
1439
1458
|
let offset = "Z";
|
|
1459
|
+
let c;
|
|
1440
1460
|
if (typeof date === "string") {
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
}
|
|
1461
|
+
if (fasttype) prep: {
|
|
1462
|
+
if (fasttype < 3) {
|
|
1463
|
+
if (+date.slice(11, 13) > 23) {
|
|
1464
|
+
date = "";
|
|
1465
|
+
break prep;
|
|
1466
|
+
}
|
|
1467
|
+
if (fasttype === 2) {
|
|
1468
|
+
offset = null;
|
|
1469
|
+
date += "Z";
|
|
1470
|
+
} else if ((c = date.charCodeAt(date.length - 1)) !== 90 && c !== 122) offset = date.slice(date.length - 6);
|
|
1471
|
+
if (unsafeDelim) date = date.slice(0, 10) + "T" + date.slice(11);
|
|
1472
|
+
} else if (fasttype === 4) date = +date.slice(0, 2) > 23 ? "" : `0000-01-01T${date}Z`;
|
|
1473
|
+
hasDate = fasttype !== 4;
|
|
1474
|
+
hasTime = fasttype !== 3;
|
|
1475
|
+
}
|
|
1476
|
+
else {
|
|
1477
|
+
let match = date.match(DATE_TIME_RE);
|
|
1478
|
+
if (match) {
|
|
1479
|
+
if (!match[1]) {
|
|
1480
|
+
hasDate = false;
|
|
1481
|
+
date = `0000-01-01T${date}`;
|
|
1482
|
+
}
|
|
1483
|
+
hasTime = !!match[2];
|
|
1484
|
+
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
1485
|
+
if (match[2] && +match[2] > 23) date = "";
|
|
1486
|
+
else {
|
|
1487
|
+
offset = match[3] || null;
|
|
1488
|
+
if (!offset && hasTime) date += "Z";
|
|
1489
|
+
}
|
|
1490
|
+
} else date = "";
|
|
1491
|
+
}
|
|
1456
1492
|
}
|
|
1457
1493
|
super(date);
|
|
1458
1494
|
if (!isNaN(this.getTime())) {
|
|
@@ -1481,7 +1517,7 @@ var TomlDate = class TomlDate extends Date {
|
|
|
1481
1517
|
if (this.isDate()) return iso.slice(0, 10);
|
|
1482
1518
|
if (this.isTime()) return iso.slice(11, 23);
|
|
1483
1519
|
if (this.#offset === null) return iso.slice(0, -1);
|
|
1484
|
-
if (this.#offset === "Z") return iso;
|
|
1520
|
+
if (this.#offset === "Z" || this.#offset === "z") return iso;
|
|
1485
1521
|
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
|
|
1486
1522
|
offset = this.#offset[0] === "-" ? offset : -offset;
|
|
1487
1523
|
return (/* @__PURE__ */ new Date(this.getTime() - offset * 6e4)).toISOString().slice(0, -1) + this.#offset;
|
|
@@ -1511,7 +1547,7 @@ var TomlDate = class TomlDate extends Date {
|
|
|
1511
1547
|
};
|
|
1512
1548
|
|
|
1513
1549
|
//#endregion
|
|
1514
|
-
//#region node_modules/smol-toml/dist/
|
|
1550
|
+
//#region node_modules/smol-toml/dist/extract.js
|
|
1515
1551
|
/*!
|
|
1516
1552
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
1517
1553
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
@@ -1539,117 +1575,147 @@ var TomlDate = class TomlDate extends Date {
|
|
|
1539
1575
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1540
1576
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1541
1577
|
*/
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
|
|
1558
|
-
if (isMultiline) {
|
|
1559
|
-
endPtr -= 2;
|
|
1560
|
-
if (str[ptr += 2] === "\r") ptr++;
|
|
1561
|
-
if (str[ptr] === "\n") ptr++;
|
|
1578
|
+
function isDigit(char, base = 10) {
|
|
1579
|
+
return base === 16 ? char > 47 && char < 58 || char > 64 && char < 71 || char > 96 && char < 103 : char > 47 && char < 48 + base;
|
|
1580
|
+
}
|
|
1581
|
+
function isEndOfValue(char, delim) {
|
|
1582
|
+
return char === 32 || char === 9 || char === 10 || char === 13 || delim && (char === delim || char === 44) || char === 35;
|
|
1583
|
+
}
|
|
1584
|
+
/** @internal */
|
|
1585
|
+
function extractValue(ctx, end) {
|
|
1586
|
+
let errPtr = ctx.p;
|
|
1587
|
+
let c = ctx.s.charCodeAt(ctx.p);
|
|
1588
|
+
if (c === 91 || c === 123) {
|
|
1589
|
+
ctx.d-- || TomlError.x("document contains excessively nested structures. aborting.", ctx);
|
|
1590
|
+
let value = c === 91 ? parseArray(ctx) : parseInlineTable(ctx);
|
|
1591
|
+
ctx.d++;
|
|
1592
|
+
return value;
|
|
1562
1593
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
if (
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
ptr = skipVoid(str, ptr - 1, true);
|
|
1596
|
-
if (str[ptr] !== "\n" && str[ptr] !== "\r") throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
1597
|
-
toml: str,
|
|
1598
|
-
ptr: tmp
|
|
1599
|
-
});
|
|
1600
|
-
ptr = skipVoid(str, ptr);
|
|
1601
|
-
} else if (c in ESC_MAP) parsed += ESC_MAP[c];
|
|
1602
|
-
else throw new TomlError("unrecognized escape sequence", {
|
|
1603
|
-
toml: str,
|
|
1604
|
-
ptr: tmp
|
|
1605
|
-
});
|
|
1606
|
-
sliceStart = ptr;
|
|
1607
|
-
} else if (!isLiteral && c === "\\") {
|
|
1608
|
-
tmp = ptr - 1;
|
|
1609
|
-
isEscape = true;
|
|
1610
|
-
parsed += str.slice(sliceStart, tmp);
|
|
1594
|
+
if (c === 34 || c === 39) return parseString(ctx);
|
|
1595
|
+
if (c === 116) {
|
|
1596
|
+
if (ctx.s.charCodeAt(++ctx.p) !== 114 || ctx.s.charCodeAt(++ctx.p) !== 117 || ctx.s.charCodeAt(++ctx.p) !== 101) TomlError.x("invalid value", ctx, errPtr);
|
|
1597
|
+
return ctx.p++, true;
|
|
1598
|
+
}
|
|
1599
|
+
if (c === 102) {
|
|
1600
|
+
if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 108 || ctx.s.charCodeAt(++ctx.p) !== 115 || ctx.s.charCodeAt(++ctx.p) !== 101) TomlError.x("invalid value", ctx, errPtr);
|
|
1601
|
+
return ctx.p++, false;
|
|
1602
|
+
}
|
|
1603
|
+
if (c === 43 || c === 45) return parseNumber(ctx, ctx.p, ctx.s.charCodeAt(++ctx.p), 44 - c, end);
|
|
1604
|
+
if (ctx.s.charCodeAt(ctx.p + 4) === 45 && ctx.s.charCodeAt(ctx.p + 7) === 45) return parseDate(ctx, c, end);
|
|
1605
|
+
if (ctx.s.charCodeAt(ctx.p + 2) === 58) return parseTime(ctx, c, end);
|
|
1606
|
+
return parseNumber(ctx, ctx.p, c, 0, end);
|
|
1607
|
+
}
|
|
1608
|
+
function parseNumber(ctx, startPtr, startChr, sign, endChr) {
|
|
1609
|
+
let c = startChr;
|
|
1610
|
+
let state = 0;
|
|
1611
|
+
let hasUnderscores = false;
|
|
1612
|
+
if (c === 105) {
|
|
1613
|
+
if (ctx.s.charCodeAt(++ctx.p) !== 110 || ctx.s.charCodeAt(++ctx.p) !== 102) TomlError.x("invalid value", ctx, startPtr);
|
|
1614
|
+
return ctx.p++, (sign || 1) / 0;
|
|
1615
|
+
}
|
|
1616
|
+
if (c === 110) {
|
|
1617
|
+
if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 110) TomlError.x("invalid value", ctx, startPtr);
|
|
1618
|
+
return ctx.p++, NaN;
|
|
1619
|
+
}
|
|
1620
|
+
if (c === 48) {
|
|
1621
|
+
if (++ctx.p >= ctx.s.length || isEndOfValue(c = ctx.s.charCodeAt(ctx.p), endChr)) return ctx.bi === true ? 0n : 0;
|
|
1622
|
+
if (!sign) {
|
|
1623
|
+
if (c === 120) return parseIntegerBaseN(ctx, startPtr, 16, endChr);
|
|
1624
|
+
else if (c === 98) return parseIntegerBaseN(ctx, startPtr, 2, endChr);
|
|
1625
|
+
else if (c === 111) return parseIntegerBaseN(ctx, startPtr, 8, endChr);
|
|
1611
1626
|
}
|
|
1627
|
+
if (c === 46) state = 2;
|
|
1628
|
+
else if (c === 101 || c === 69) state = 4;
|
|
1629
|
+
else TomlError.x("illegal leading zero", ctx, startPtr);
|
|
1630
|
+
} else if (!isDigit(c)) TomlError.x("invalid value", ctx, startPtr);
|
|
1631
|
+
while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
|
|
1632
|
+
if (!state) state = 1;
|
|
1633
|
+
if (c === 95) {
|
|
1634
|
+
if (!(state & 1)) TomlError.x("illegal underscore", ctx);
|
|
1635
|
+
state += 11;
|
|
1636
|
+
hasUnderscores = true;
|
|
1637
|
+
} else if (state === 1 && c === 46) state = 2;
|
|
1638
|
+
else if ((state === 1 || state === 3) && (c === 101 || c === 69)) state = 4;
|
|
1639
|
+
else if (state === 4 && (c === 43 || c === 45)) state = 6;
|
|
1640
|
+
else if (!isDigit(c)) TomlError.x(`illegal character in numeric literal`, ctx);
|
|
1641
|
+
else if (state > 9) state -= 11;
|
|
1642
|
+
else if (!(state & 1)) state++;
|
|
1643
|
+
}
|
|
1644
|
+
if (!state) {
|
|
1645
|
+
let val = (startChr - 48) * (sign || 1);
|
|
1646
|
+
return ctx.bi === true ? BigInt(val) : val;
|
|
1647
|
+
}
|
|
1648
|
+
if (!(state & 1)) TomlError.x("unfinished numeric value", ctx, startPtr);
|
|
1649
|
+
let str = ctx.s.slice(startPtr, ctx.p);
|
|
1650
|
+
if (hasUnderscores) str = str.replaceAll("_", "");
|
|
1651
|
+
return state > 1 ? parseFloat(str) : parseInteger(ctx, str, 10, startPtr);
|
|
1652
|
+
}
|
|
1653
|
+
function parseIntegerBaseN(ctx, startPtr, base, endChr) {
|
|
1654
|
+
let c, underscore = 1;
|
|
1655
|
+
while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) if (c === 95) {
|
|
1656
|
+
if (underscore & 1) TomlError.x("illegal underscore", ctx);
|
|
1657
|
+
underscore = 3;
|
|
1658
|
+
} else if (!isDigit(c, base)) TomlError.x(`illegal character in numeric literal`, ctx);
|
|
1659
|
+
else if (underscore & 1) underscore--;
|
|
1660
|
+
if (underscore & 1) TomlError.x("unfinished numeric value", ctx);
|
|
1661
|
+
let str = ctx.s.slice(startPtr + 2, ctx.p);
|
|
1662
|
+
if (underscore) str = str.replaceAll("_", "");
|
|
1663
|
+
return parseInteger(ctx, str, base, startPtr);
|
|
1664
|
+
}
|
|
1665
|
+
function parseInteger(ctx, str, base, startPtr) {
|
|
1666
|
+
if (ctx.bi !== true) int: {
|
|
1667
|
+
let val = parseInt(str, base);
|
|
1668
|
+
if (!Number.isSafeInteger(val)) {
|
|
1669
|
+
if (ctx.bi) break int;
|
|
1670
|
+
TomlError.x("integer value cannot be represented losslessly", ctx, startPtr);
|
|
1671
|
+
}
|
|
1672
|
+
return val;
|
|
1673
|
+
}
|
|
1674
|
+
return base === 10 ? BigInt(str) : BigInt((base === 2 ? "0b" : base === 8 ? "0o" : "0x") + str);
|
|
1675
|
+
}
|
|
1676
|
+
function parseDate(ctx, c, endChr) {
|
|
1677
|
+
let startPtr = ctx.p++, unsafeSeparator;
|
|
1678
|
+
if (!isDigit(c) || !isDigit(ctx.s.charCodeAt(ctx.p++)) || !isDigit(ctx.s.charCodeAt(ctx.p++)) || !isDigit(ctx.s.charCodeAt(ctx.p++))) return parseNumber(ctx, ctx.p = startPtr, c, 0, endChr);
|
|
1679
|
+
ctx.p += 5;
|
|
1680
|
+
if (!isDigit(ctx.s.charCodeAt(ctx.p++))) TomlError.x("invalid date-time: date part is malformed", ctx, startPtr);
|
|
1681
|
+
if (ctx.p >= ctx.s.length || ((c = ctx.s.charCodeAt(ctx.p)) !== 32 || (unsafeSeparator = true, !isDigit(ctx.s.charCodeAt(ctx.p + 1)))) && c !== 84 && c !== 116) return readDate(ctx, ctx.s.slice(startPtr, ctx.p), 3, false, startPtr);
|
|
1682
|
+
if (ctx.s.charCodeAt(ctx.p += 3) !== 58) TomlError.x("invalid date-time: time part is malformed", ctx, startPtr);
|
|
1683
|
+
if (ctx.s.charCodeAt(ctx.p += 3) === 58) ctx.p += 3;
|
|
1684
|
+
if (ctx.s.charCodeAt(ctx.p) === 46) while (isDigit(ctx.s.charCodeAt(++ctx.p)));
|
|
1685
|
+
if (c = ctx.s.charCodeAt(ctx.p)) {
|
|
1686
|
+
if (c === 90 || c === 122) return readDate(ctx, ctx.s.slice(startPtr, ++ctx.p), 1, unsafeSeparator, startPtr, "[+00:00]");
|
|
1687
|
+
if (c === 43 || c === 45) return readDate(ctx, ctx.s.slice(startPtr, ctx.p += 6), 1, unsafeSeparator, startPtr, !ctx.ld && "[" + ctx.s.slice(ctx.p - 6, ctx.p) + "]");
|
|
1688
|
+
}
|
|
1689
|
+
return readDate(ctx, ctx.s.slice(startPtr, ctx.p), 2, unsafeSeparator, startPtr);
|
|
1690
|
+
}
|
|
1691
|
+
function parseTime(ctx, c, endChr) {
|
|
1692
|
+
let start = ctx.p;
|
|
1693
|
+
if (!isDigit(c) || !isDigit(ctx.s.charCodeAt(++ctx.p))) return parseNumber(ctx, --ctx.p, c, 0, endChr);
|
|
1694
|
+
if (ctx.s.charCodeAt(ctx.p += 4) === 58) ctx.p += 3;
|
|
1695
|
+
if (ctx.s.charCodeAt(ctx.p) === 46) while (isDigit(ctx.s.charCodeAt(++ctx.p)));
|
|
1696
|
+
return readDate(ctx, ctx.s.slice(start, ctx.p), 4, false, start);
|
|
1697
|
+
}
|
|
1698
|
+
function readDate(ctx, str, type, unsafeDelim, errPtr, temporalSuffix) {
|
|
1699
|
+
if (ctx.ld) {
|
|
1700
|
+
let date = new TomlDate(str, type, unsafeDelim);
|
|
1701
|
+
if (!date.isValid()) TomlError.x("invalid date", ctx, errPtr);
|
|
1702
|
+
return date;
|
|
1612
1703
|
}
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
if (value === "nan" || value === "+nan" || value === "-nan") return NaN;
|
|
1621
|
-
if (value === "-0") return integersAsBigInt ? 0n : 0;
|
|
1622
|
-
let isInt = INT_REGEX.test(value);
|
|
1623
|
-
if (isInt || FLOAT_REGEX.test(value)) {
|
|
1624
|
-
if (LEADING_ZERO.test(value)) throw new TomlError("leading zeroes are not allowed", {
|
|
1625
|
-
toml,
|
|
1626
|
-
ptr
|
|
1627
|
-
});
|
|
1628
|
-
value = value.replace(/_/g, "");
|
|
1629
|
-
let numeric = +value;
|
|
1630
|
-
if (isNaN(numeric)) throw new TomlError("invalid number", {
|
|
1631
|
-
toml,
|
|
1632
|
-
ptr
|
|
1633
|
-
});
|
|
1634
|
-
if (isInt) {
|
|
1635
|
-
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) throw new TomlError("integer value cannot be represented losslessly", {
|
|
1636
|
-
toml,
|
|
1637
|
-
ptr
|
|
1638
|
-
});
|
|
1639
|
-
if (isInt || integersAsBigInt === true) numeric = BigInt(value);
|
|
1704
|
+
try {
|
|
1705
|
+
if (temporalSuffix) str += temporalSuffix;
|
|
1706
|
+
switch (type) {
|
|
1707
|
+
case 1: return Temporal.ZonedDateTime.from(str);
|
|
1708
|
+
case 2: return Temporal.PlainDateTime.from(str);
|
|
1709
|
+
case 3: return Temporal.PlainDate.from(str);
|
|
1710
|
+
case 4: return Temporal.PlainTime.from(str);
|
|
1640
1711
|
}
|
|
1641
|
-
|
|
1712
|
+
} catch (e) {
|
|
1713
|
+
TomlError.x(e instanceof Error ? e.message : "" + e, ctx, errPtr);
|
|
1642
1714
|
}
|
|
1643
|
-
const date = new TomlDate(value);
|
|
1644
|
-
if (!date.isValid()) throw new TomlError("invalid value", {
|
|
1645
|
-
toml,
|
|
1646
|
-
ptr
|
|
1647
|
-
});
|
|
1648
|
-
return date;
|
|
1649
1715
|
}
|
|
1650
1716
|
|
|
1651
1717
|
//#endregion
|
|
1652
|
-
//#region node_modules/smol-toml/dist/
|
|
1718
|
+
//#region node_modules/smol-toml/dist/util.js
|
|
1653
1719
|
/*!
|
|
1654
1720
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
1655
1721
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
@@ -1677,66 +1743,26 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
|
1677
1743
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1678
1744
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1679
1745
|
*/
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
if (!allowNewLines) {
|
|
1689
|
-
let newlineIdx = value.indexOf("\n", trimmed.length);
|
|
1690
|
-
if (newlineIdx > -1) throw new TomlError("newlines are not allowed in inline tables", {
|
|
1691
|
-
toml: str,
|
|
1692
|
-
ptr: startPtr + newlineIdx
|
|
1693
|
-
});
|
|
1694
|
-
}
|
|
1695
|
-
return [trimmed, commentIdx];
|
|
1696
|
-
}
|
|
1697
|
-
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
1698
|
-
if (depth === 0) throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
1699
|
-
toml: str,
|
|
1700
|
-
ptr
|
|
1701
|
-
});
|
|
1702
|
-
let c = str[ptr];
|
|
1703
|
-
if (c === "[" || c === "{") {
|
|
1704
|
-
let [value, endPtr] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
1705
|
-
let newPtr = end ? skipUntil(str, endPtr, ",", end) : endPtr;
|
|
1706
|
-
if (endPtr - newPtr && end === "}") {
|
|
1707
|
-
let nextNewLine = indexOfNewline(str, endPtr, newPtr);
|
|
1708
|
-
if (nextNewLine > -1) throw new TomlError("newlines are not allowed in inline tables", {
|
|
1709
|
-
toml: str,
|
|
1710
|
-
ptr: nextNewLine
|
|
1711
|
-
});
|
|
1712
|
-
}
|
|
1713
|
-
return [value, newPtr];
|
|
1714
|
-
}
|
|
1715
|
-
let endPtr;
|
|
1716
|
-
if (c === "\"" || c === "'") {
|
|
1717
|
-
endPtr = getStringEnd(str, ptr);
|
|
1718
|
-
let parsed = parseString(str, ptr, endPtr);
|
|
1719
|
-
if (end) {
|
|
1720
|
-
endPtr = skipVoid(str, endPtr, end !== "]");
|
|
1721
|
-
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") throw new TomlError("unexpected character encountered", {
|
|
1722
|
-
toml: str,
|
|
1723
|
-
ptr: endPtr
|
|
1724
|
-
});
|
|
1725
|
-
endPtr += +(str[endPtr] === ",");
|
|
1746
|
+
/** @internal */
|
|
1747
|
+
function skipComment(ctx) {
|
|
1748
|
+
for (; ctx.p < ctx.s.length; ctx.p++) {
|
|
1749
|
+
let c = ctx.s.charCodeAt(ctx.p);
|
|
1750
|
+
if (c === 10) break;
|
|
1751
|
+
if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
|
|
1752
|
+
ctx.p++;
|
|
1753
|
+
break;
|
|
1726
1754
|
}
|
|
1727
|
-
|
|
1755
|
+
if (c < 32 && c !== 9 || c === 127) TomlError.x("control characters are not allowed in comments", ctx);
|
|
1728
1756
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
endPtr += +(str[endPtr] === ",");
|
|
1757
|
+
}
|
|
1758
|
+
/** @internal */
|
|
1759
|
+
function skipVoid(ctx, banNewLines, banComments) {
|
|
1760
|
+
let c;
|
|
1761
|
+
while (ctx.p < ctx.s.length) {
|
|
1762
|
+
while (ctx.p < ctx.s.length && ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10))) ctx.p++;
|
|
1763
|
+
if (banComments || c !== 35) break;
|
|
1764
|
+
skipComment(ctx);
|
|
1738
1765
|
}
|
|
1739
|
-
return [parseValue(slice[0], str, ptr, integersAsBigInt), endPtr];
|
|
1740
1766
|
}
|
|
1741
1767
|
|
|
1742
1768
|
//#endregion
|
|
@@ -1768,132 +1794,99 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
|
1768
1794
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1769
1795
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1770
1796
|
*/
|
|
1771
|
-
|
|
1772
|
-
function parseKey(
|
|
1773
|
-
let
|
|
1797
|
+
/** @internal */
|
|
1798
|
+
function parseKey(ctx, end = 61) {
|
|
1799
|
+
let startPtr;
|
|
1800
|
+
let state = 0;
|
|
1774
1801
|
let parsed = [];
|
|
1775
|
-
let
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
if (c
|
|
1783
|
-
if (
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
let newLine = indexOfNewline(strEnd);
|
|
1796
|
-
if (newLine > -1) throw new TomlError("newlines are not allowed in keys", {
|
|
1797
|
-
toml: str,
|
|
1798
|
-
ptr: ptr + dot + newLine
|
|
1799
|
-
});
|
|
1800
|
-
if (strEnd.trimStart()) throw new TomlError("found extra tokens after the string part", {
|
|
1801
|
-
toml: str,
|
|
1802
|
-
ptr: eos
|
|
1803
|
-
});
|
|
1804
|
-
if (endPtr < eos) {
|
|
1805
|
-
endPtr = str.indexOf(end, eos);
|
|
1806
|
-
if (endPtr < 0) throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
1807
|
-
toml: str,
|
|
1808
|
-
ptr
|
|
1809
|
-
});
|
|
1810
|
-
}
|
|
1811
|
-
parsed.push(parseString(str, ptr, eos));
|
|
1812
|
-
} else {
|
|
1813
|
-
dot = str.indexOf(".", ptr);
|
|
1814
|
-
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
1815
|
-
if (!KEY_PART_RE.test(part)) throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
|
|
1816
|
-
toml: str,
|
|
1817
|
-
ptr
|
|
1818
|
-
});
|
|
1819
|
-
parsed.push(part.trimEnd());
|
|
1802
|
+
let sliceStart;
|
|
1803
|
+
let c = ctx.s.charCodeAt(startPtr = ctx.p);
|
|
1804
|
+
do
|
|
1805
|
+
if (c === end) {
|
|
1806
|
+
if (!state) TomlError.x("unexpected end of key", ctx);
|
|
1807
|
+
if (state === 1) parsed.push(ctx.s.slice(sliceStart, ctx.p));
|
|
1808
|
+
return ctx.p++, parsed;
|
|
1809
|
+
} else if (c === 46) {
|
|
1810
|
+
if (!state) TomlError.x("illegal empty bare key", ctx);
|
|
1811
|
+
if (state === 1) parsed.push(ctx.s.slice(sliceStart, ctx.p));
|
|
1812
|
+
state = 0;
|
|
1813
|
+
} else if (!state && (c === 34 || c === 39)) {
|
|
1814
|
+
if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2)) TomlError.x("illegal quoted key: multiline strings are not allowed", ctx);
|
|
1815
|
+
parsed.push(parseString(ctx));
|
|
1816
|
+
state = 2;
|
|
1817
|
+
ctx.p--;
|
|
1818
|
+
} else if (c === 32 || c === 9) {
|
|
1819
|
+
if (state === 1) {
|
|
1820
|
+
parsed.push(ctx.s.slice(sliceStart, ctx.p));
|
|
1821
|
+
state = 2;
|
|
1820
1822
|
}
|
|
1823
|
+
} else if (state === 2 || c < 48 && c !== 45 || c > 57 && c < 65 || c > 90 && c < 97 && c !== 95 || c > 122) TomlError.x("illegal character in key", ctx);
|
|
1824
|
+
else if (!state) {
|
|
1825
|
+
state = 1;
|
|
1826
|
+
sliceStart = ctx.p;
|
|
1821
1827
|
}
|
|
1822
|
-
|
|
1823
|
-
|
|
1828
|
+
while (c = ctx.s.charCodeAt(++ctx.p));
|
|
1829
|
+
TomlError.x("incomplete key-value: cannot find end of key", ctx, startPtr);
|
|
1824
1830
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1831
|
+
/** @internal */
|
|
1832
|
+
function parseInlineTable(ctx) {
|
|
1833
|
+
let startPtr = ctx.p++;
|
|
1834
|
+
let res = Object.create(null);
|
|
1827
1835
|
let seen = /* @__PURE__ */ new Set();
|
|
1828
1836
|
let c;
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
toml: str,
|
|
1849
|
-
ptr
|
|
1850
|
-
});
|
|
1851
|
-
if (!hasOwn && k === "__proto__") Object.defineProperty(t, k, {
|
|
1852
|
-
enumerable: true,
|
|
1853
|
-
configurable: true,
|
|
1854
|
-
writable: true
|
|
1855
|
-
});
|
|
1837
|
+
while (ctx.p < ctx.s.length) {
|
|
1838
|
+
skipVoid(ctx);
|
|
1839
|
+
if ((c = ctx.s.charCodeAt(ctx.p)) === 125) {
|
|
1840
|
+
ctx.p++;
|
|
1841
|
+
return res;
|
|
1842
|
+
}
|
|
1843
|
+
let k;
|
|
1844
|
+
let t = res;
|
|
1845
|
+
let hasOwn = false;
|
|
1846
|
+
let errPtr = ctx.p;
|
|
1847
|
+
let key = parseKey(ctx);
|
|
1848
|
+
for (let i = 0; i < key.length; i++) {
|
|
1849
|
+
if (i) t = hasOwn ? t[k] : t[k] = Object.create(null);
|
|
1850
|
+
k = key[i];
|
|
1851
|
+
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) TomlError.x("trying to redefine an already defined value", ctx, errPtr);
|
|
1852
|
+
let unsafe = k === "__proto__";
|
|
1853
|
+
if (ctx.uk && (unsafe || k === "constructor")) {
|
|
1854
|
+
t = ctx.uk !== 1 && TomlError.x("document contains an unsafe property", ctx, errPtr);
|
|
1855
|
+
break;
|
|
1856
1856
|
}
|
|
1857
|
-
if (hasOwn
|
|
1858
|
-
|
|
1859
|
-
|
|
1857
|
+
if (!hasOwn && unsafe) Object.defineProperty(t, k, {
|
|
1858
|
+
enumerable: true,
|
|
1859
|
+
configurable: true,
|
|
1860
|
+
writable: true
|
|
1860
1861
|
});
|
|
1861
|
-
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
|
|
1862
|
-
seen.add(value);
|
|
1863
|
-
t[k] = value;
|
|
1864
|
-
ptr = valueEndPtr;
|
|
1865
|
-
comma = str[ptr - 1] === "," ? ptr - 1 : 0;
|
|
1866
1862
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
function parseArray(
|
|
1863
|
+
if (hasOwn) TomlError.x("trying to redefine an already defined value", ctx, errPtr);
|
|
1864
|
+
skipVoid(ctx, true, true);
|
|
1865
|
+
let value = extractValue(ctx, 125);
|
|
1866
|
+
if (t && typeof (t[k] = value) === "object") seen.add(value);
|
|
1867
|
+
skipVoid(ctx);
|
|
1868
|
+
if ((c = ctx.s.charCodeAt(ctx.p++)) === 125) return res;
|
|
1869
|
+
if (c !== 44) TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
|
|
1870
|
+
}
|
|
1871
|
+
TomlError.x("unfinished table", ctx, startPtr);
|
|
1872
|
+
}
|
|
1873
|
+
/** @internal */
|
|
1874
|
+
function parseArray(ctx) {
|
|
1875
|
+
let startPtr = ctx.p++;
|
|
1879
1876
|
let res = [];
|
|
1880
1877
|
let c;
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
toml: str,
|
|
1894
|
-
ptr
|
|
1895
|
-
});
|
|
1896
|
-
return [res, ptr];
|
|
1878
|
+
while (ctx.p < ctx.s.length) {
|
|
1879
|
+
skipVoid(ctx);
|
|
1880
|
+
if ((c = ctx.s.charCodeAt(ctx.p)) === 93) {
|
|
1881
|
+
ctx.p++;
|
|
1882
|
+
return res;
|
|
1883
|
+
}
|
|
1884
|
+
res.push(extractValue(ctx, 93));
|
|
1885
|
+
skipVoid(ctx);
|
|
1886
|
+
if ((c = ctx.s.charCodeAt(ctx.p++)) === 93) return res;
|
|
1887
|
+
if (c !== 44) TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
|
|
1888
|
+
}
|
|
1889
|
+
TomlError.x("unfinished array", ctx, startPtr);
|
|
1897
1890
|
}
|
|
1898
1891
|
|
|
1899
1892
|
//#endregion
|
|
@@ -1925,7 +1918,7 @@ function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
|
1925
1918
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1926
1919
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1927
1920
|
*/
|
|
1928
|
-
function peekTable(key, table, meta, type) {
|
|
1921
|
+
function peekTable(ctx, key, table, meta, type) {
|
|
1929
1922
|
let t = table;
|
|
1930
1923
|
let m = meta;
|
|
1931
1924
|
let k;
|
|
@@ -1933,7 +1926,7 @@ function peekTable(key, table, meta, type) {
|
|
|
1933
1926
|
let state;
|
|
1934
1927
|
for (let i = 0; i < key.length; i++) {
|
|
1935
1928
|
if (i) {
|
|
1936
|
-
t = hasOwn ? t[k] : t[k] =
|
|
1929
|
+
t = hasOwn ? t[k] : t[k] = Object.create(null);
|
|
1937
1930
|
m = (state = m[k]).c;
|
|
1938
1931
|
if (type === 0 && (state.t === 1 || state.t === 2)) return null;
|
|
1939
1932
|
if (state.t === 2) {
|
|
@@ -1945,7 +1938,9 @@ function peekTable(key, table, meta, type) {
|
|
|
1945
1938
|
k = key[i];
|
|
1946
1939
|
if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) return null;
|
|
1947
1940
|
if (!hasOwn) {
|
|
1948
|
-
|
|
1941
|
+
let unsafe = k === "__proto__";
|
|
1942
|
+
if (ctx.uk && (unsafe || k === "constructor")) return false;
|
|
1943
|
+
if (unsafe) {
|
|
1949
1944
|
Object.defineProperty(t, k, {
|
|
1950
1945
|
enumerable: true,
|
|
1951
1946
|
configurable: true,
|
|
@@ -1961,7 +1956,7 @@ function peekTable(key, table, meta, type) {
|
|
|
1961
1956
|
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
1962
1957
|
d: false,
|
|
1963
1958
|
i: 0,
|
|
1964
|
-
c:
|
|
1959
|
+
c: Object.create(null)
|
|
1965
1960
|
};
|
|
1966
1961
|
}
|
|
1967
1962
|
}
|
|
@@ -1972,17 +1967,17 @@ function peekTable(key, table, meta, type) {
|
|
|
1972
1967
|
state.d = true;
|
|
1973
1968
|
t[k] = [];
|
|
1974
1969
|
}
|
|
1975
|
-
t[k].push(t =
|
|
1970
|
+
t[k].push(t = Object.create(null));
|
|
1976
1971
|
state.c[state.i++] = state = {
|
|
1977
1972
|
t: 1,
|
|
1978
1973
|
d: false,
|
|
1979
1974
|
i: 0,
|
|
1980
|
-
c:
|
|
1975
|
+
c: Object.create(null)
|
|
1981
1976
|
};
|
|
1982
1977
|
}
|
|
1983
1978
|
if (state.d) return null;
|
|
1984
1979
|
state.d = true;
|
|
1985
|
-
if (type === 1) t = hasOwn ? t[k] : t[k] =
|
|
1980
|
+
if (type === 1) t = hasOwn ? t[k] : t[k] = Object.create(null);
|
|
1986
1981
|
else if (type === 0 && hasOwn) return null;
|
|
1987
1982
|
return [
|
|
1988
1983
|
k,
|
|
@@ -1990,47 +1985,55 @@ function peekTable(key, table, meta, type) {
|
|
|
1990
1985
|
state.c
|
|
1991
1986
|
];
|
|
1992
1987
|
}
|
|
1993
|
-
function
|
|
1994
|
-
|
|
1995
|
-
|
|
1988
|
+
function validateTablePeek(ctx, peek, ptr) {
|
|
1989
|
+
if (peek === null || ctx.uk === 2) TomlError.x(peek === null ? "trying to redefine an already defined table or value" : "document contains an unsafe property", ctx, ptr);
|
|
1990
|
+
}
|
|
1991
|
+
function parse$1(toml, options = {}) {
|
|
1992
|
+
let ctx = {
|
|
1993
|
+
s: toml,
|
|
1994
|
+
p: 0,
|
|
1995
|
+
d: options.maxDepth ?? 1e3,
|
|
1996
|
+
bi: options.integersAsBigInt ?? false,
|
|
1997
|
+
ld: options.useLegacyDate ?? true,
|
|
1998
|
+
uk: options.unsafeKeyBehaviour === "throw" ? 2 : options.unsafeKeyBehaviour === "drop" ? 1 : 0
|
|
1999
|
+
};
|
|
2000
|
+
let res = Object.create(null);
|
|
2001
|
+
let meta = Object.create(null);
|
|
2002
|
+
let tmp;
|
|
2003
|
+
let skipping = false;
|
|
1996
2004
|
let tbl = res;
|
|
1997
2005
|
let m = meta;
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2006
|
+
if (toml.charCodeAt(0) === 65279) ctx.p++;
|
|
2007
|
+
skipVoid(ctx);
|
|
2008
|
+
while (ctx.p < toml.length) {
|
|
2009
|
+
if (toml.charCodeAt(ctx.p) === 91) {
|
|
2010
|
+
let isTableArray = toml.charCodeAt(++ctx.p) === 91;
|
|
2011
|
+
tmp = ctx.p += +isTableArray;
|
|
2012
|
+
skipping = false;
|
|
2013
|
+
let k = parseKey(ctx, 93);
|
|
2002
2014
|
if (isTableArray) {
|
|
2003
|
-
if (toml
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2015
|
+
if (toml.charCodeAt(ctx.p) !== 93) TomlError.x("expected end of table array declaration", ctx);
|
|
2016
|
+
ctx.p++;
|
|
2017
|
+
}
|
|
2018
|
+
let p = peekTable(ctx, k, res, meta, isTableArray ? 2 : 1);
|
|
2019
|
+
if (!p) {
|
|
2020
|
+
validateTablePeek(ctx, p, tmp);
|
|
2021
|
+
skipping = true;
|
|
2022
|
+
} else {
|
|
2023
|
+
m = p[2];
|
|
2024
|
+
tbl = p[1];
|
|
2008
2025
|
}
|
|
2009
|
-
let p = peekTable(k[0], res, meta, isTableArray ? 2 : 1);
|
|
2010
|
-
if (!p) throw new TomlError("trying to redefine an already defined table or value", {
|
|
2011
|
-
toml,
|
|
2012
|
-
ptr
|
|
2013
|
-
});
|
|
2014
|
-
m = p[2];
|
|
2015
|
-
tbl = p[1];
|
|
2016
|
-
ptr = k[1];
|
|
2017
2026
|
} else {
|
|
2018
|
-
|
|
2019
|
-
let p = peekTable(
|
|
2020
|
-
if (!p
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
2025
|
-
p[1][p[0]] = v[0];
|
|
2026
|
-
ptr = v[1];
|
|
2027
|
+
tmp = ctx.p;
|
|
2028
|
+
let p = peekTable(ctx, parseKey(ctx), tbl, m, 0);
|
|
2029
|
+
if (!p && !skipping) validateTablePeek(ctx, p, tmp);
|
|
2030
|
+
skipVoid(ctx, true, true);
|
|
2031
|
+
let v = extractValue(ctx, void 0);
|
|
2032
|
+
if (p && !skipping) p[1][p[0]] = v;
|
|
2027
2033
|
}
|
|
2028
|
-
|
|
2029
|
-
if (toml
|
|
2030
|
-
|
|
2031
|
-
ptr
|
|
2032
|
-
});
|
|
2033
|
-
ptr = skipVoid(toml, ptr);
|
|
2034
|
+
skipVoid(ctx, true);
|
|
2035
|
+
if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && (tmp !== 13 || toml.charCodeAt(ctx.p + 1) !== 10)) TomlError.x("each key-value declaration must be followed by an end-of-line", ctx);
|
|
2036
|
+
skipVoid(ctx);
|
|
2034
2037
|
}
|
|
2035
2038
|
return res;
|
|
2036
2039
|
}
|
|
@@ -2065,11 +2068,20 @@ function parse$1(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
2065
2068
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
2066
2069
|
*/
|
|
2067
2070
|
let BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
2071
|
+
let HAS_WELLFORMED = !!"".isWellFormed;
|
|
2068
2072
|
function extendedTypeOf(obj) {
|
|
2069
2073
|
let type = typeof obj;
|
|
2070
2074
|
if (type === "object") {
|
|
2071
2075
|
if (Array.isArray(obj)) return "array";
|
|
2072
|
-
if (obj instanceof Date) return "date";
|
|
2076
|
+
if (typeof obj.getUTCDate === "function" && obj instanceof Date) return "date";
|
|
2077
|
+
if (globalThis.Temporal) {
|
|
2078
|
+
if (obj.until) {
|
|
2079
|
+
if (obj instanceof Temporal.ZonedDateTime) return "temporal/tz+uc";
|
|
2080
|
+
if (obj instanceof Temporal.PlainDateTime || obj instanceof Temporal.PlainDate) return "temporal/uc";
|
|
2081
|
+
if (obj instanceof Temporal.PlainTime || obj instanceof Temporal.Instant) return "temporal";
|
|
2082
|
+
if (obj instanceof Temporal.PlainYearMonth) return "temporal/x";
|
|
2083
|
+
} else if (obj.toPlainDate && obj instanceof Temporal.PlainMonthDay || obj.negated && obj instanceof Temporal.Duration) return "temporal/x";
|
|
2084
|
+
}
|
|
2073
2085
|
}
|
|
2074
2086
|
return type;
|
|
2075
2087
|
}
|
|
@@ -2077,61 +2089,79 @@ function isArrayOfTables(obj) {
|
|
|
2077
2089
|
for (let i = 0; i < obj.length; i++) if (extendedTypeOf(obj[i]) !== "object") return false;
|
|
2078
2090
|
return obj.length != 0;
|
|
2079
2091
|
}
|
|
2092
|
+
function formatWellFormedStringUnchecked(s) {
|
|
2093
|
+
return JSON.stringify(s).replaceAll("", "\\u007f");
|
|
2094
|
+
}
|
|
2080
2095
|
function formatString(s) {
|
|
2081
|
-
return
|
|
2096
|
+
return formatWellFormedStringUnchecked(HAS_WELLFORMED ? s.toWellFormed() : s);
|
|
2082
2097
|
}
|
|
2083
|
-
function
|
|
2098
|
+
function formatKey(s) {
|
|
2099
|
+
if (BARE_KEY.test(s)) return s;
|
|
2100
|
+
if (HAS_WELLFORMED && !s.isWellFormed()) throw new RangeError("key contains illegal lone surrogates");
|
|
2101
|
+
return formatWellFormedStringUnchecked(s);
|
|
2102
|
+
}
|
|
2103
|
+
function stringifyValue(val, type, depth, numberAsFloat, strictTemporal) {
|
|
2084
2104
|
if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2105
|
+
switch (type) {
|
|
2106
|
+
case "number":
|
|
2107
|
+
if (isNaN(val)) return "nan";
|
|
2108
|
+
if (val === Infinity) return "inf";
|
|
2109
|
+
if (val === -Infinity) return "-inf";
|
|
2110
|
+
if (Number.isInteger(val) && (numberAsFloat || !Number.isSafeInteger(val))) return val.toFixed(1);
|
|
2111
|
+
case "bigint":
|
|
2112
|
+
case "boolean":
|
|
2113
|
+
case "temporal": return val.toString();
|
|
2114
|
+
case "string": return formatString(val);
|
|
2115
|
+
case "date":
|
|
2116
|
+
if (isNaN(val.getTime())) throw new TypeError("cannot serialize invalid date");
|
|
2117
|
+
return val.toISOString();
|
|
2118
|
+
case "object": return stringifyInlineTable(val, depth, numberAsFloat, strictTemporal);
|
|
2119
|
+
case "array": return stringifyArray(val, depth, numberAsFloat, strictTemporal);
|
|
2120
|
+
case "temporal/tz+uc": if (strictTemporal) {
|
|
2121
|
+
let tz = val.timeZoneId;
|
|
2122
|
+
let tzc = tz.charCodeAt(0);
|
|
2123
|
+
if (tzc !== 43 && tzc !== 45 && (tzc !== 85 && tzc !== 71 && tzc !== 90 && tzc !== 69 || tz !== "UTC" && tz !== "UCT" && tz !== "Universal" && tz !== "Zulu" && !tz.startsWith("GMT") && tz !== "Greenwich" && !tz.startsWith("Etc/"))) throw new TypeError("Temporal objects with an IANA timezone are not allowed in Temporal strict mode");
|
|
2124
|
+
}
|
|
2125
|
+
case "temporal/uc":
|
|
2126
|
+
if (strictTemporal && val.calendarId !== "iso8601") throw new TypeError("Temporal objects with a non-default calendar are not allowed in Temporal strict mode");
|
|
2127
|
+
return val.toString({
|
|
2128
|
+
calendarName: "never",
|
|
2129
|
+
timeZoneName: "never"
|
|
2130
|
+
});
|
|
2131
|
+
case "temporal/x": throw new TypeError("Unsupported " + val[Symbol.toStringTag]);
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
function stringifyInlineTable(obj, depth, numberAsFloat, strictTemporal) {
|
|
2102
2135
|
let keys = Object.keys(obj);
|
|
2103
2136
|
if (keys.length === 0) return "{}";
|
|
2104
2137
|
let res = "{ ";
|
|
2105
2138
|
for (let i = 0; i < keys.length; i++) {
|
|
2106
2139
|
let k = keys[i];
|
|
2107
2140
|
if (i) res += ", ";
|
|
2108
|
-
res +=
|
|
2109
|
-
res += " = ";
|
|
2110
|
-
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
2141
|
+
res += formatKey(k) + " = " + stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat, strictTemporal);
|
|
2111
2142
|
}
|
|
2112
2143
|
return res + " }";
|
|
2113
2144
|
}
|
|
2114
|
-
function stringifyArray(array, depth, numberAsFloat) {
|
|
2145
|
+
function stringifyArray(array, depth, numberAsFloat, strictTemporal) {
|
|
2115
2146
|
if (array.length === 0) return "[]";
|
|
2116
2147
|
let res = "[ ";
|
|
2117
2148
|
for (let i = 0; i < array.length; i++) {
|
|
2118
2149
|
if (i) res += ", ";
|
|
2119
2150
|
if (array[i] === null || array[i] === void 0) throw new TypeError("arrays cannot contain null or undefined values");
|
|
2120
|
-
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
2151
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat, strictTemporal);
|
|
2121
2152
|
}
|
|
2122
2153
|
return res + " ]";
|
|
2123
2154
|
}
|
|
2124
|
-
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
2155
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat, strictTemporal) {
|
|
2125
2156
|
if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
2126
2157
|
let res = "";
|
|
2127
2158
|
for (let i = 0; i < array.length; i++) {
|
|
2128
|
-
res +=
|
|
2129
|
-
res += stringifyTable(array[i], key, depth, numberAsFloat);
|
|
2130
|
-
res += "\n\n";
|
|
2159
|
+
res += `${res && "\n"}[[${key}]]\n`;
|
|
2160
|
+
res += stringifyTable(0, array[i], key, depth, numberAsFloat, strictTemporal);
|
|
2131
2161
|
}
|
|
2132
2162
|
return res;
|
|
2133
2163
|
}
|
|
2134
|
-
function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
|
2164
|
+
function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat, strictTemporal) {
|
|
2135
2165
|
if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
2136
2166
|
let preamble = "";
|
|
2137
2167
|
let tables = "";
|
|
@@ -2141,39 +2171,78 @@ function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
|
|
2141
2171
|
if (obj[k] !== null && obj[k] !== void 0) {
|
|
2142
2172
|
let type = extendedTypeOf(obj[k]);
|
|
2143
2173
|
if (type === "symbol" || type === "function") throw new TypeError(`cannot serialize values of type '${type}'`);
|
|
2144
|
-
let key =
|
|
2145
|
-
if (type === "array" && isArrayOfTables(obj[k])) tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
2174
|
+
let key = formatKey(k);
|
|
2175
|
+
if (type === "array" && isArrayOfTables(obj[k])) tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat, strictTemporal);
|
|
2146
2176
|
else if (type === "object") {
|
|
2147
2177
|
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
2148
|
-
tables +=
|
|
2149
|
-
tables += stringifyTable(obj[k], tblKey, depth - 1, numberAsFloat);
|
|
2150
|
-
tables += "\n\n";
|
|
2178
|
+
tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat, strictTemporal);
|
|
2151
2179
|
} else {
|
|
2152
2180
|
preamble += key;
|
|
2153
2181
|
preamble += " = ";
|
|
2154
|
-
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
2182
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat, strictTemporal);
|
|
2155
2183
|
preamble += "\n";
|
|
2156
2184
|
}
|
|
2157
2185
|
}
|
|
2158
2186
|
}
|
|
2159
|
-
|
|
2187
|
+
if (tableKey && (preamble || !tables)) preamble = preamble ? `[${tableKey}]\n${preamble}` : `[${tableKey}]`;
|
|
2188
|
+
return preamble && tables ? `${preamble}\n${tables}` : preamble || tables;
|
|
2160
2189
|
}
|
|
2161
|
-
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
2190
|
+
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false, strictTemporal = false } = {}) {
|
|
2162
2191
|
if (extendedTypeOf(obj) !== "object") throw new TypeError("stringify can only be called with an object");
|
|
2163
|
-
|
|
2192
|
+
let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat, strictTemporal);
|
|
2193
|
+
if (str[str.length - 1] !== "\n") return str + "\n";
|
|
2194
|
+
return str;
|
|
2164
2195
|
}
|
|
2165
2196
|
|
|
2197
|
+
//#endregion
|
|
2198
|
+
//#region node_modules/smol-toml/dist/index.js
|
|
2199
|
+
/*!
|
|
2200
|
+
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
2201
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
2202
|
+
*
|
|
2203
|
+
* Redistribution and use in source and binary forms, with or without
|
|
2204
|
+
* modification, are permitted provided that the following conditions are met:
|
|
2205
|
+
*
|
|
2206
|
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
2207
|
+
* list of conditions and the following disclaimer.
|
|
2208
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
2209
|
+
* this list of conditions and the following disclaimer in the
|
|
2210
|
+
* documentation and/or other materials provided with the distribution.
|
|
2211
|
+
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
2212
|
+
* may be used to endorse or promote products derived from this software without
|
|
2213
|
+
* specific prior written permission.
|
|
2214
|
+
*
|
|
2215
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
2216
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
2217
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
2218
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
2219
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
2220
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
2221
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
2222
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
2223
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
2224
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
2225
|
+
*/
|
|
2226
|
+
|
|
2166
2227
|
//#endregion
|
|
2167
2228
|
//#region src/config.js
|
|
2168
2229
|
async function assertSafePath(path) {
|
|
2169
|
-
|
|
2170
|
-
|
|
2230
|
+
const full = resolve(path);
|
|
2231
|
+
let current = parse(full).root;
|
|
2232
|
+
for (const part of full.slice(current.length).split(/[\\/]/).filter(Boolean)) {
|
|
2171
2233
|
current = join(current, part);
|
|
2234
|
+
let info;
|
|
2172
2235
|
try {
|
|
2173
|
-
|
|
2236
|
+
info = await lstat(current);
|
|
2174
2237
|
} catch (error) {
|
|
2175
|
-
if (error.code
|
|
2238
|
+
if (error.code === "ENOENT") return;
|
|
2239
|
+
throw error;
|
|
2176
2240
|
}
|
|
2241
|
+
if (!info.isSymbolicLink()) continue;
|
|
2242
|
+
if (current === full) throw new Error(`Refusing symbolic link: ${current}`);
|
|
2243
|
+
await stat(current).catch((error) => {
|
|
2244
|
+
throw error.code === "ENOENT" ? /* @__PURE__ */ new Error(`Refusing dangling symbolic link: ${current}`) : error;
|
|
2245
|
+
});
|
|
2177
2246
|
}
|
|
2178
2247
|
}
|
|
2179
2248
|
async function readConfig(path) {
|
|
@@ -2188,6 +2257,8 @@ async function readConfig(path) {
|
|
|
2188
2257
|
function object(value) {
|
|
2189
2258
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2190
2259
|
}
|
|
2260
|
+
const plain$1 = (value) => Array.isArray(value) ? value.map(plain$1) : value !== null && typeof value === "object" && Object.getPrototypeOf(value) === null ? Object.fromEntries(Object.entries(value).map(([key, item]) => [key, plain$1(item)])) : value;
|
|
2261
|
+
const parseToml = (text) => plain$1(parse$1(text));
|
|
2191
2262
|
function parseJson(text, path) {
|
|
2192
2263
|
const errors = [];
|
|
2193
2264
|
const value = parse$2(text ?? "{}", errors, { allowTrailingComma: true });
|
|
@@ -2215,7 +2286,7 @@ function editJson(text, changes, path) {
|
|
|
2215
2286
|
function updateToml(text, desired, path, obsolete = []) {
|
|
2216
2287
|
const before = text ?? "";
|
|
2217
2288
|
try {
|
|
2218
|
-
|
|
2289
|
+
parseToml(before);
|
|
2219
2290
|
} catch {
|
|
2220
2291
|
throw new Error(`Invalid TOML in ${path}; nothing overwritten.`);
|
|
2221
2292
|
}
|
|
@@ -2240,7 +2311,7 @@ function updateToml(text, desired, path, obsolete = []) {
|
|
|
2240
2311
|
}
|
|
2241
2312
|
let block = lines[i], parsed;
|
|
2242
2313
|
for (;;) try {
|
|
2243
|
-
parsed =
|
|
2314
|
+
parsed = parseToml(block);
|
|
2244
2315
|
break;
|
|
2245
2316
|
} catch {
|
|
2246
2317
|
if (++i >= lines.length) throw new Error(`Cannot safely update TOML in ${path}.`);
|
|
@@ -2275,7 +2346,7 @@ function updateToml(text, desired, path, obsolete = []) {
|
|
|
2275
2346
|
else if (char === "=") break;
|
|
2276
2347
|
}
|
|
2277
2348
|
const rawKey = block.slice(0, equal).trim();
|
|
2278
|
-
let cursor =
|
|
2349
|
+
let cursor = parseToml(`${rawKey} = 0`), keys = [];
|
|
2279
2350
|
while (object(cursor)) {
|
|
2280
2351
|
const key = Object.keys(cursor)[0];
|
|
2281
2352
|
keys.push(key);
|
|
@@ -2309,7 +2380,7 @@ function updateToml(text, desired, path, obsolete = []) {
|
|
|
2309
2380
|
}
|
|
2310
2381
|
const leaves = (value, prefix = []) => Object.entries(value).flatMap(([key, item]) => object(item) ? leaves(item, [...prefix, key]) : [[[...prefix, key], item]]);
|
|
2311
2382
|
for (const [keys, value] of leaves(desired)) {
|
|
2312
|
-
const current =
|
|
2383
|
+
const current = parseToml(statements.map((item) => item.text).join(eol));
|
|
2313
2384
|
if (isDeepStrictEqual(valueAt(current, keys), value)) continue;
|
|
2314
2385
|
let header = -1, prefix = [];
|
|
2315
2386
|
statements.forEach((item, index) => {
|
|
@@ -2326,7 +2397,7 @@ function updateToml(text, desired, path, obsolete = []) {
|
|
|
2326
2397
|
});
|
|
2327
2398
|
}
|
|
2328
2399
|
const after = statements.map((item) => item.text).join(eol);
|
|
2329
|
-
const result =
|
|
2400
|
+
const result = parseToml(after);
|
|
2330
2401
|
for (const [keys, value] of leaves(desired)) if (!isDeepStrictEqual(valueAt(result, keys), value)) throw new Error(`Cannot safely update ${keys.join(".")} in ${path}.`);
|
|
2331
2402
|
return after === before ? before : `${after.replace(/\s+$/, "")}${eol}`;
|
|
2332
2403
|
}
|
|
@@ -2380,9 +2451,50 @@ async function writeChange(change) {
|
|
|
2380
2451
|
|
|
2381
2452
|
//#endregion
|
|
2382
2453
|
//#region src/assistants.js
|
|
2383
|
-
const
|
|
2384
|
-
const
|
|
2385
|
-
|
|
2454
|
+
const VERCEL = "https://ai-gateway.vercel.sh";
|
|
2455
|
+
const PROVIDERS = {
|
|
2456
|
+
vercel: {
|
|
2457
|
+
id: "vercel",
|
|
2458
|
+
name: "Vercel AI Gateway",
|
|
2459
|
+
label: "Vercel AI Gateway",
|
|
2460
|
+
model: "callstack/apex",
|
|
2461
|
+
envVar: "AI_GATEWAY_API_KEY",
|
|
2462
|
+
keyName: "your Vercel AI Gateway API key",
|
|
2463
|
+
keysUrl: "https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai-gateway&title=AI+Gateway",
|
|
2464
|
+
guideUrl: "https://vercel.com/docs/ai-gateway/coding-agents",
|
|
2465
|
+
baseUrl: `${VERCEL}/coding-agent/v1`,
|
|
2466
|
+
codexUrl: `${VERCEL}/codex/v1`,
|
|
2467
|
+
cursorUrl: `${VERCEL}/cursor/v1`,
|
|
2468
|
+
anthropicUrl: `${VERCEL}/claude-code`,
|
|
2469
|
+
appUrl: `${VERCEL}/v1`,
|
|
2470
|
+
opencode: "apex-vercel",
|
|
2471
|
+
pi: "apex-vercel",
|
|
2472
|
+
codex: "apex_vercel"
|
|
2473
|
+
},
|
|
2474
|
+
callstack: {
|
|
2475
|
+
id: "callstack",
|
|
2476
|
+
name: "Callstack portal",
|
|
2477
|
+
label: "callstack.ai",
|
|
2478
|
+
model: "callstack/Apex",
|
|
2479
|
+
envVar: "CALLSTACK_AUTH_TOKEN",
|
|
2480
|
+
keyName: "your callstack.ai key",
|
|
2481
|
+
keysUrl: null,
|
|
2482
|
+
guideUrl: "https://app.notion.com/p/callstack/Apex-how-to-use-it-36d5d027c0f880e99d03d1c37a77382f",
|
|
2483
|
+
baseUrl: "https://api.callstack.ai/v1",
|
|
2484
|
+
codexUrl: "https://api.callstack.ai/v1",
|
|
2485
|
+
cursorUrl: "https://api.callstack.ai/v1",
|
|
2486
|
+
anthropicUrl: "https://api.callstack.ai",
|
|
2487
|
+
appUrl: "https://api.callstack.ai/v1",
|
|
2488
|
+
opencode: "callstack.ai",
|
|
2489
|
+
pi: "callstack",
|
|
2490
|
+
codex: "callstack_ai"
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
const PROVIDER_IDS = Object.keys(PROVIDERS);
|
|
2494
|
+
function defaultProvider(env = process.env) {
|
|
2495
|
+
const keyed = PROVIDER_IDS.filter((id) => env[PROVIDERS[id].envVar]?.trim());
|
|
2496
|
+
return PROVIDERS[keyed.length === 1 ? keyed[0] : "vercel"];
|
|
2497
|
+
}
|
|
2386
2498
|
const IDS = [
|
|
2387
2499
|
"opencode",
|
|
2388
2500
|
"codex",
|
|
@@ -2431,30 +2543,25 @@ const OPENCODE_MODEL = {
|
|
|
2431
2543
|
options: { reasoningEffort: "medium" },
|
|
2432
2544
|
variants: Object.fromEntries(EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
|
|
2433
2545
|
};
|
|
2434
|
-
const
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
settings: { reasoningEffort:
|
|
2450
|
-
|
|
2451
|
-
id: effort,
|
|
2452
|
-
settings: { reasoningEffort: effort }
|
|
2453
|
-
}))
|
|
2454
|
-
} }
|
|
2546
|
+
const OPENCODE_V2_PACKAGE = "@opencode/ai/providers/openai-compatible";
|
|
2547
|
+
const OPENCODE_V2_MODEL = {
|
|
2548
|
+
name: "Apex",
|
|
2549
|
+
capabilities: {
|
|
2550
|
+
tools: true,
|
|
2551
|
+
input: ["text", "image"],
|
|
2552
|
+
output: ["text"]
|
|
2553
|
+
},
|
|
2554
|
+
limit: {
|
|
2555
|
+
context: CONTEXT_WINDOW,
|
|
2556
|
+
output: MAX_OUTPUT
|
|
2557
|
+
},
|
|
2558
|
+
settings: { reasoningEffort: "medium" },
|
|
2559
|
+
variants: EFFORTS.map((effort) => ({
|
|
2560
|
+
id: effort,
|
|
2561
|
+
settings: { reasoningEffort: effort }
|
|
2562
|
+
}))
|
|
2455
2563
|
};
|
|
2456
2564
|
const PI_MODEL = {
|
|
2457
|
-
id: MODEL,
|
|
2458
2565
|
reasoning: true,
|
|
2459
2566
|
input: ["text", "image"],
|
|
2460
2567
|
thinkingLevelMap: {
|
|
@@ -2561,16 +2668,17 @@ async function detect(options = {}) {
|
|
|
2561
2668
|
};
|
|
2562
2669
|
}));
|
|
2563
2670
|
}
|
|
2564
|
-
async function openCodeHasKey(authFile) {
|
|
2671
|
+
async function openCodeHasKey(authFile, providerId) {
|
|
2565
2672
|
if (!authFile) return false;
|
|
2566
2673
|
try {
|
|
2567
|
-
return Object.hasOwn(JSON.parse(await readConfig(authFile) ?? "{}"),
|
|
2674
|
+
return Object.hasOwn(JSON.parse(await readConfig(authFile) ?? "{}"), providerId);
|
|
2568
2675
|
} catch {
|
|
2569
2676
|
return false;
|
|
2570
2677
|
}
|
|
2571
2678
|
}
|
|
2572
2679
|
const PI_PLACEHOLDER = "XXX";
|
|
2573
|
-
async function planAssistant(assistant) {
|
|
2680
|
+
async function planAssistant(assistant, provider = PROVIDERS.vercel) {
|
|
2681
|
+
const { model, envVar } = provider;
|
|
2574
2682
|
const changes = [];
|
|
2575
2683
|
const json = async (filename, updates) => {
|
|
2576
2684
|
const path = join(assistant.directory, filename);
|
|
@@ -2589,124 +2697,131 @@ async function planAssistant(assistant) {
|
|
|
2589
2697
|
const hasJsonc = await exists(join(assistant.directory, "opencode.jsonc"));
|
|
2590
2698
|
if (hasJson && hasJsonc) throw new Error("Both opencode.json and opencode.jsonc exist. Consolidate them before init.");
|
|
2591
2699
|
let v2 = false;
|
|
2592
|
-
const
|
|
2700
|
+
const id = provider.opencode;
|
|
2701
|
+
const storedKey = await openCodeHasKey(assistant.authFile, id);
|
|
2593
2702
|
await json(hasJsonc ? "opencode.jsonc" : "opencode.json", (existing) => {
|
|
2594
2703
|
v2 = Object.hasOwn(existing, "providers");
|
|
2595
2704
|
if (v2) return [
|
|
2596
2705
|
[[
|
|
2597
2706
|
"providers",
|
|
2598
|
-
|
|
2707
|
+
id,
|
|
2599
2708
|
"name"
|
|
2600
|
-
],
|
|
2709
|
+
], provider.label],
|
|
2601
2710
|
[[
|
|
2602
2711
|
"providers",
|
|
2603
|
-
|
|
2712
|
+
id,
|
|
2604
2713
|
"package"
|
|
2605
|
-
],
|
|
2714
|
+
], OPENCODE_V2_PACKAGE],
|
|
2606
2715
|
[[
|
|
2607
2716
|
"providers",
|
|
2608
|
-
|
|
2717
|
+
id,
|
|
2609
2718
|
"settings",
|
|
2610
2719
|
"baseURL"
|
|
2611
|
-
],
|
|
2612
|
-
...Object.entries(
|
|
2720
|
+
], provider.baseUrl],
|
|
2721
|
+
...Object.entries(OPENCODE_V2_MODEL).map(([key, value]) => [[
|
|
2613
2722
|
"providers",
|
|
2614
|
-
|
|
2723
|
+
id,
|
|
2615
2724
|
"models",
|
|
2616
|
-
|
|
2725
|
+
model,
|
|
2617
2726
|
key
|
|
2618
2727
|
], key === "settings" ? {
|
|
2619
|
-
...existing.providers?.[
|
|
2728
|
+
...existing.providers?.[id]?.models?.[model]?.settings,
|
|
2620
2729
|
...value
|
|
2621
2730
|
} : value])
|
|
2622
2731
|
];
|
|
2623
2732
|
return [
|
|
2624
2733
|
[[
|
|
2625
2734
|
"provider",
|
|
2626
|
-
|
|
2735
|
+
id,
|
|
2627
2736
|
"npm"
|
|
2628
2737
|
], "@ai-sdk/openai-compatible"],
|
|
2629
2738
|
[[
|
|
2630
2739
|
"provider",
|
|
2631
|
-
|
|
2740
|
+
id,
|
|
2632
2741
|
"name"
|
|
2633
|
-
],
|
|
2742
|
+
], provider.label],
|
|
2634
2743
|
[[
|
|
2635
2744
|
"provider",
|
|
2636
|
-
|
|
2745
|
+
id,
|
|
2637
2746
|
"options",
|
|
2638
2747
|
"baseURL"
|
|
2639
|
-
],
|
|
2640
|
-
...storedKey || existing.provider?.[
|
|
2748
|
+
], provider.baseUrl],
|
|
2749
|
+
...storedKey || existing.provider?.[id]?.options?.apiKey ? [] : [[[
|
|
2641
2750
|
"provider",
|
|
2642
|
-
|
|
2751
|
+
id,
|
|
2643
2752
|
"options",
|
|
2644
2753
|
"apiKey"
|
|
2645
|
-
],
|
|
2754
|
+
], `{env:${envVar}}`]],
|
|
2646
2755
|
...Object.entries(OPENCODE_MODEL).map(([key, value]) => [[
|
|
2647
2756
|
"provider",
|
|
2648
|
-
|
|
2757
|
+
id,
|
|
2649
2758
|
"models",
|
|
2650
|
-
|
|
2759
|
+
model,
|
|
2651
2760
|
key
|
|
2652
2761
|
], key === "options" ? {
|
|
2653
|
-
...existing.provider?.[
|
|
2762
|
+
...existing.provider?.[id]?.models?.[model]?.options,
|
|
2654
2763
|
...value
|
|
2655
2764
|
} : value])
|
|
2656
2765
|
];
|
|
2657
2766
|
});
|
|
2658
|
-
if (v2) changes[0].steps = [
|
|
2767
|
+
if (v2) changes[0].steps = [`OpenCode 2 stores provider keys itself: run /connect in OpenCode, pick ${provider.label} → "Manually enter API Key", and paste ${provider.keyName}.`];
|
|
2659
2768
|
break;
|
|
2660
2769
|
}
|
|
2661
|
-
case "pi":
|
|
2770
|
+
case "pi": {
|
|
2771
|
+
const id = provider.pi;
|
|
2772
|
+
const entry = {
|
|
2773
|
+
id: model,
|
|
2774
|
+
...PI_MODEL
|
|
2775
|
+
};
|
|
2662
2776
|
await json("models.json", (existing) => {
|
|
2663
|
-
const models = existing.providers?.
|
|
2664
|
-
const key = existing.providers?.
|
|
2665
|
-
if (!Array.isArray(models) || models.some((
|
|
2777
|
+
const models = existing.providers?.[id]?.models ?? [];
|
|
2778
|
+
const key = existing.providers?.[id]?.apiKey;
|
|
2779
|
+
if (!Array.isArray(models) || models.some((item) => !item || typeof item.id !== "string")) throw new Error("Expected Pi models to be an array of model objects.");
|
|
2666
2780
|
return [
|
|
2667
2781
|
[[
|
|
2668
2782
|
"providers",
|
|
2669
|
-
|
|
2783
|
+
id,
|
|
2670
2784
|
"baseUrl"
|
|
2671
|
-
],
|
|
2785
|
+
], provider.baseUrl],
|
|
2672
2786
|
[[
|
|
2673
2787
|
"providers",
|
|
2674
|
-
|
|
2788
|
+
id,
|
|
2675
2789
|
"api"
|
|
2676
2790
|
], "openai-completions"],
|
|
2677
2791
|
...key && key !== PI_PLACEHOLDER ? [] : [[[
|
|
2678
2792
|
"providers",
|
|
2679
|
-
|
|
2793
|
+
id,
|
|
2680
2794
|
"apiKey"
|
|
2681
|
-
],
|
|
2795
|
+
], `$${envVar}`]],
|
|
2682
2796
|
[[
|
|
2683
2797
|
"providers",
|
|
2684
|
-
|
|
2798
|
+
id,
|
|
2685
2799
|
"models"
|
|
2686
|
-
], models.some((
|
|
2687
|
-
...
|
|
2688
|
-
...
|
|
2689
|
-
...
|
|
2690
|
-
} :
|
|
2800
|
+
], models.some((item) => item.id === model) ? models.map((item) => item.id === model ? {
|
|
2801
|
+
...item,
|
|
2802
|
+
...entry,
|
|
2803
|
+
...item.compat ? { compat: Object.fromEntries(Object.entries(item.compat).filter(([key]) => key !== "reasoningEffortMap")) } : {}
|
|
2804
|
+
} : item) : [...models, entry]]
|
|
2691
2805
|
];
|
|
2692
2806
|
});
|
|
2693
|
-
await json("settings.json", [[["modelThinkingLevels",
|
|
2807
|
+
await json("settings.json", [[["modelThinkingLevels", `${id}/${model}`], "medium"]]);
|
|
2694
2808
|
break;
|
|
2809
|
+
}
|
|
2695
2810
|
case "claude":
|
|
2696
2811
|
await json("settings.json", [[["env", "CLAUDE_CODE_ATTRIBUTION_HEADER"], "0"]]);
|
|
2697
2812
|
break;
|
|
2698
2813
|
case "codex": {
|
|
2699
|
-
const path = join(assistant.directory,
|
|
2814
|
+
const path = join(assistant.directory, `${provider.codex}.config.toml`);
|
|
2700
2815
|
const before = await readConfig(path);
|
|
2701
2816
|
const after = updateToml(before, {
|
|
2702
|
-
model_provider:
|
|
2703
|
-
model
|
|
2817
|
+
model_provider: provider.codex,
|
|
2818
|
+
model,
|
|
2704
2819
|
model_context_window: CONTEXT_WINDOW,
|
|
2705
2820
|
model_reasoning_effort: "medium",
|
|
2706
|
-
model_providers: {
|
|
2707
|
-
name:
|
|
2708
|
-
base_url:
|
|
2709
|
-
env_key:
|
|
2821
|
+
model_providers: { [provider.codex]: {
|
|
2822
|
+
name: provider.label,
|
|
2823
|
+
base_url: provider.codexUrl,
|
|
2824
|
+
env_key: envVar,
|
|
2710
2825
|
wire_api: "responses",
|
|
2711
2826
|
requires_openai_auth: false
|
|
2712
2827
|
} }
|
|
@@ -2722,25 +2837,26 @@ async function planAssistant(assistant) {
|
|
|
2722
2837
|
}
|
|
2723
2838
|
return changes;
|
|
2724
2839
|
}
|
|
2725
|
-
function launchOptions(id, env = process.env) {
|
|
2726
|
-
const
|
|
2727
|
-
|
|
2840
|
+
function launchOptions(id, env = process.env, provider = defaultProvider(env)) {
|
|
2841
|
+
const { model, envVar } = provider;
|
|
2842
|
+
const token = env[envVar];
|
|
2843
|
+
if (!token?.trim()) throw new Error(`Set ${envVar} in your environment before launching with ${provider.name}.`);
|
|
2728
2844
|
const childEnv = { ...env };
|
|
2729
2845
|
switch (id) {
|
|
2730
2846
|
case "opencode": return {
|
|
2731
|
-
args: ["--model",
|
|
2847
|
+
args: ["--model", `${provider.opencode}/${model}`],
|
|
2732
2848
|
env: childEnv
|
|
2733
2849
|
};
|
|
2734
2850
|
case "codex": return {
|
|
2735
|
-
args: ["--profile",
|
|
2851
|
+
args: ["--profile", provider.codex],
|
|
2736
2852
|
env: childEnv
|
|
2737
2853
|
};
|
|
2738
2854
|
case "pi": return {
|
|
2739
2855
|
args: [
|
|
2740
2856
|
"--provider",
|
|
2741
|
-
|
|
2857
|
+
provider.pi,
|
|
2742
2858
|
"--model",
|
|
2743
|
-
|
|
2859
|
+
model,
|
|
2744
2860
|
"--thinking",
|
|
2745
2861
|
"medium"
|
|
2746
2862
|
],
|
|
@@ -2755,33 +2871,33 @@ function launchOptions(id, env = process.env) {
|
|
|
2755
2871
|
"CLAUDE_CODE_USE_FOUNDRY"
|
|
2756
2872
|
]) delete childEnv[key];
|
|
2757
2873
|
Object.assign(childEnv, {
|
|
2758
|
-
ANTHROPIC_BASE_URL:
|
|
2874
|
+
ANTHROPIC_BASE_URL: provider.anthropicUrl,
|
|
2759
2875
|
ANTHROPIC_AUTH_TOKEN: token,
|
|
2760
|
-
ANTHROPIC_MODEL:
|
|
2876
|
+
ANTHROPIC_MODEL: model,
|
|
2761
2877
|
CLAUDE_CODE_ATTRIBUTION_HEADER: "0",
|
|
2762
|
-
ANTHROPIC_DEFAULT_OPUS_MODEL:
|
|
2763
|
-
ANTHROPIC_DEFAULT_SONNET_MODEL:
|
|
2764
|
-
ANTHROPIC_DEFAULT_HAIKU_MODEL:
|
|
2765
|
-
CLAUDE_CODE_SUBAGENT_MODEL:
|
|
2878
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: model,
|
|
2879
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: model,
|
|
2880
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
|
|
2881
|
+
CLAUDE_CODE_SUBAGENT_MODEL: model,
|
|
2766
2882
|
CLAUDE_CODE_MAX_CONTEXT_TOKENS: String(CONTEXT_WINDOW),
|
|
2767
2883
|
CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(MAX_OUTPUT)
|
|
2768
2884
|
});
|
|
2769
2885
|
return {
|
|
2770
|
-
args: ["--model",
|
|
2886
|
+
args: ["--model", model],
|
|
2771
2887
|
env: childEnv
|
|
2772
2888
|
};
|
|
2773
2889
|
default: throw new Error(`Cannot launch ${id}. Use the editor's model selector.`);
|
|
2774
2890
|
}
|
|
2775
2891
|
}
|
|
2776
2892
|
const RUN_NOTE = { claude: "(ANTHROPIC_* gateway environment set)" };
|
|
2777
|
-
function runExpansion(id) {
|
|
2778
|
-
const { args } = launchOptions(id, {
|
|
2893
|
+
function runExpansion(id, provider) {
|
|
2894
|
+
const { args } = launchOptions(id, { [provider.envVar]: "placeholder" }, provider);
|
|
2779
2895
|
return [`${id} ${args.join(" ")}`, RUN_NOTE[id]].filter(Boolean).join(" ");
|
|
2780
2896
|
}
|
|
2781
|
-
const
|
|
2782
|
-
id:
|
|
2897
|
+
const copilotModel = (provider) => JSON.stringify({
|
|
2898
|
+
id: provider.model,
|
|
2783
2899
|
name: "Apex",
|
|
2784
|
-
url:
|
|
2900
|
+
url: provider.baseUrl,
|
|
2785
2901
|
toolCalling: true,
|
|
2786
2902
|
vision: true,
|
|
2787
2903
|
thinking: true,
|
|
@@ -2790,32 +2906,39 @@ const COPILOT_MODEL = JSON.stringify({
|
|
|
2790
2906
|
supportsReasoningEffort: EFFORTS,
|
|
2791
2907
|
reasoningEffortFormat: "chat-completions"
|
|
2792
2908
|
}, null, 2);
|
|
2793
|
-
const
|
|
2909
|
+
const aiSdkSnippet = (provider) => [
|
|
2794
2910
|
"import { createOpenAI } from '@ai-sdk/openai';",
|
|
2795
2911
|
"",
|
|
2796
2912
|
"const apex = createOpenAI({",
|
|
2797
2913
|
" name: 'callstack',",
|
|
2798
|
-
` baseURL: '${
|
|
2799
|
-
|
|
2914
|
+
` baseURL: '${provider.appUrl}',`,
|
|
2915
|
+
` apiKey: process.env.${provider.envVar},`,
|
|
2800
2916
|
"});",
|
|
2801
2917
|
"const requestOptions = {",
|
|
2802
|
-
` model: apex('${
|
|
2918
|
+
` model: apex('${provider.model}'),`,
|
|
2803
2919
|
` maxOutputTokens: ${MAX_OUTPUT},`,
|
|
2804
2920
|
"};",
|
|
2805
2921
|
"// Pass requestOptions with your prompt to generateText / streamText.",
|
|
2806
2922
|
`// Reasoning effort (${EFFORTS.join(", ")}):`,
|
|
2807
2923
|
"// providerOptions: { callstack: { reasoningEffort: 'medium' } }"
|
|
2808
2924
|
];
|
|
2809
|
-
const
|
|
2810
|
-
cursor
|
|
2811
|
-
copilot
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2925
|
+
const MANUAL_IDS = [
|
|
2926
|
+
"cursor",
|
|
2927
|
+
"copilot",
|
|
2928
|
+
"ai-sdk"
|
|
2929
|
+
];
|
|
2930
|
+
function manualSteps(id, provider) {
|
|
2931
|
+
switch (id) {
|
|
2932
|
+
case "cursor": return [`Cursor: Settings → Models → API Keys → OpenAI API Key. Enter ${provider.keyName}, override the base URL with ${provider.cursorUrl}, add and enable ${provider.model}, then select it in Agent.`, "Cursor has no way to declare what a custom model can do (tool calling, vision, reasoning); it infers that itself."];
|
|
2933
|
+
case "copilot": return [
|
|
2934
|
+
`Installation of Copilot itself is not verified: Copilot → model selector → Manage Models → Add Models → Custom Endpoint → name ${provider.label} → enter ${provider.keyName} → Chat Completions.`,
|
|
2935
|
+
"Keep the generated apiKey secret reference; add this object to its models array:",
|
|
2936
|
+
...copilotModel(provider).split("\n")
|
|
2937
|
+
];
|
|
2938
|
+
case "ai-sdk": return [`Apex CLI never writes your key into a project. Keep it in ${provider.envVar} (for example in a .env that git ignores) and create the provider with:`, ...aiSdkSnippet(provider)];
|
|
2939
|
+
default: throw new Error(`${id} is set up automatically.`);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2819
2942
|
|
|
2820
2943
|
//#endregion
|
|
2821
2944
|
//#region node_modules/fast-string-truncated-width/dist/utils.js
|
|
@@ -3514,6 +3637,32 @@ var a = class extends y {
|
|
|
3514
3637
|
});
|
|
3515
3638
|
}
|
|
3516
3639
|
};
|
|
3640
|
+
let n$1 = class n extends y {
|
|
3641
|
+
options;
|
|
3642
|
+
cursor = 0;
|
|
3643
|
+
get _selectedValue() {
|
|
3644
|
+
return this.options[this.cursor];
|
|
3645
|
+
}
|
|
3646
|
+
changeValue() {
|
|
3647
|
+
const e = this._selectedValue;
|
|
3648
|
+
this.value = e === void 0 ? void 0 : e.value;
|
|
3649
|
+
}
|
|
3650
|
+
constructor(e) {
|
|
3651
|
+
super(e, false), this.options = e.options;
|
|
3652
|
+
const o = this.options.findIndex(({ value: s }) => s === e.initialValue), t = o === -1 ? 0 : o;
|
|
3653
|
+
this.cursor = this.options[t]?.disabled ? findCursor(t, 1, this.options) : t, this.changeValue(), this.on("cursor", (s) => {
|
|
3654
|
+
switch (s) {
|
|
3655
|
+
case "left":
|
|
3656
|
+
case "up":
|
|
3657
|
+
this.cursor = findCursor(this.cursor, -1, this.options);
|
|
3658
|
+
break;
|
|
3659
|
+
case "down":
|
|
3660
|
+
case "right": this.cursor = findCursor(this.cursor, 1, this.options);
|
|
3661
|
+
}
|
|
3662
|
+
this.changeValue();
|
|
3663
|
+
});
|
|
3664
|
+
}
|
|
3665
|
+
};
|
|
3517
3666
|
|
|
3518
3667
|
//#endregion
|
|
3519
3668
|
//#region node_modules/@clack/prompts/dist/index.mjs
|
|
@@ -3745,6 +3894,63 @@ const u = {
|
|
|
3745
3894
|
block: unicodeOr("█", "#")
|
|
3746
3895
|
};
|
|
3747
3896
|
const SELECT_INSTRUCTIONS = [`${styleText("dim", "↑/↓")} to navigate`, `${styleText("dim", "Enter:")} confirm`];
|
|
3897
|
+
const c = (t, o) => t.includes(`
|
|
3898
|
+
`) ? t.split(`
|
|
3899
|
+
`).map((d) => o(d)).join(`
|
|
3900
|
+
`) : o(t);
|
|
3901
|
+
const select = (t) => {
|
|
3902
|
+
const o = (n, m) => {
|
|
3903
|
+
if (n === void 0) return "";
|
|
3904
|
+
const s = n.label ?? String(n.value);
|
|
3905
|
+
switch (m) {
|
|
3906
|
+
case "disabled": return `${styleText("gray", S_RADIO_INACTIVE)} ${c(s, (i) => styleText("gray", i))}${n.hint ? ` ${styleText("dim", `(${n.hint ?? "disabled"})`)}` : ""}`;
|
|
3907
|
+
case "selected": return `${c(s, (i) => styleText("dim", i))}`;
|
|
3908
|
+
case "active": return `${styleText("green", S_RADIO_ACTIVE)} ${s}${n.hint ? ` ${styleText("dim", `(${n.hint})`)}` : ""}`;
|
|
3909
|
+
case "cancelled": return `${c(s, (i) => styleText(["strikethrough", "dim"], i))}`;
|
|
3910
|
+
default: return `${styleText("dim", S_RADIO_INACTIVE)} ${c(s, (i) => styleText("dim", i))}`;
|
|
3911
|
+
}
|
|
3912
|
+
}, d = t.showInstructions ?? true;
|
|
3913
|
+
return new n$1({
|
|
3914
|
+
options: t.options,
|
|
3915
|
+
signal: t.signal,
|
|
3916
|
+
input: t.input,
|
|
3917
|
+
output: t.output,
|
|
3918
|
+
initialValue: t.initialValue,
|
|
3919
|
+
render() {
|
|
3920
|
+
const n = t.withGuide ?? settings.withGuide, m = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, i = wrapTextWithPrefix(t.output, t.message, s, m), u = `${n ? `${styleText("gray", S_BAR)}
|
|
3921
|
+
` : ""}${i}
|
|
3922
|
+
`;
|
|
3923
|
+
switch (this.state) {
|
|
3924
|
+
case "submit": {
|
|
3925
|
+
const r = n ? `${styleText("gray", S_BAR)} ` : "";
|
|
3926
|
+
return `${u}${wrapTextWithPrefix(t.output, o(this.options[this.cursor], "selected"), r)}`;
|
|
3927
|
+
}
|
|
3928
|
+
case "cancel": {
|
|
3929
|
+
const r = n ? `${styleText("gray", S_BAR)} ` : "";
|
|
3930
|
+
return `${u}${wrapTextWithPrefix(t.output, o(this.options[this.cursor], "cancelled"), r)}${n ? `
|
|
3931
|
+
${styleText("gray", S_BAR)}` : ""}`;
|
|
3932
|
+
}
|
|
3933
|
+
default: {
|
|
3934
|
+
const r = n ? `${styleText("cyan", S_BAR)} ` : "", a = u.split(`
|
|
3935
|
+
`).length, p = d ? formatInstructionFooter(SELECT_INSTRUCTIONS, n) : n ? [styleText("cyan", S_BAR_END)] : [], f = p.join(`
|
|
3936
|
+
`), b = p.length + 1;
|
|
3937
|
+
return `${u}${r}${limitOptions({
|
|
3938
|
+
output: t.output,
|
|
3939
|
+
cursor: this.cursor,
|
|
3940
|
+
options: this.options,
|
|
3941
|
+
maxItems: t.maxItems,
|
|
3942
|
+
columnPadding: r.length,
|
|
3943
|
+
rowPadding: a + b,
|
|
3944
|
+
style: (g, x) => o(g, g.disabled ? "disabled" : x ? "active" : "inactive")
|
|
3945
|
+
}).join(`
|
|
3946
|
+
${r}`)}
|
|
3947
|
+
${f}
|
|
3948
|
+
`;
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
}).prompt();
|
|
3953
|
+
};
|
|
3748
3954
|
const i = `${styleText("gray", S_BAR)} `;
|
|
3749
3955
|
|
|
3750
3956
|
//#endregion
|
|
@@ -3792,7 +3998,7 @@ const maskChanges = (changes, secret) => changes.map((change) => ({
|
|
|
3792
3998
|
//#region src/diff.js
|
|
3793
3999
|
function readValues(text, format) {
|
|
3794
4000
|
if (format === "toml") try {
|
|
3795
|
-
return
|
|
4001
|
+
return parseToml(text);
|
|
3796
4002
|
} catch {
|
|
3797
4003
|
throw new Error("Invalid TOML while reading values.");
|
|
3798
4004
|
}
|
|
@@ -4001,7 +4207,8 @@ const pad = (text, column) => {
|
|
|
4001
4207
|
const value = String(text);
|
|
4002
4208
|
return value + " ".repeat(Math.max(1, column - visible(value).length));
|
|
4003
4209
|
};
|
|
4004
|
-
const
|
|
4210
|
+
const MODELS = [...new Set(Object.values(PROVIDERS).map((provider) => provider.model))].map((id) => id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
4211
|
+
const MODEL_PATTERN = new RegExp(`(?<![\\w/.-])(?:${MODELS.join("|")})(?![\\w-])`, "g");
|
|
4005
4212
|
const model = (text) => String(text).replace(MODEL_PATTERN, (match) => green(match));
|
|
4006
4213
|
const STATUS_COLUMN = columnWidth(Object.values(STATUS).map((status) => status.word));
|
|
4007
4214
|
function clip(text, limit) {
|
|
@@ -4105,9 +4312,21 @@ function bullet(marker, message) {
|
|
|
4105
4312
|
const success = (message) => bullet(green("✔"), message);
|
|
4106
4313
|
const warn = (message) => bullet(yellow("!"), message);
|
|
4107
4314
|
const error = (message) => bullet(red("✖"), message);
|
|
4108
|
-
async function
|
|
4315
|
+
async function selectProvider(options, initial) {
|
|
4316
|
+
const chosen = await select({
|
|
4317
|
+
message: "Which gateway should your assistants use for Apex?",
|
|
4318
|
+
options,
|
|
4319
|
+
initialValue: initial
|
|
4320
|
+
});
|
|
4321
|
+
if (isCancel(chosen)) {
|
|
4322
|
+
cancel("Cancelled. Nothing was written.");
|
|
4323
|
+
return false;
|
|
4324
|
+
}
|
|
4325
|
+
return chosen;
|
|
4326
|
+
}
|
|
4327
|
+
async function selectAssistants(options, initial, modelId) {
|
|
4109
4328
|
const chosen = await multiselect({
|
|
4110
|
-
message: model(`Set up ${
|
|
4329
|
+
message: model(`Set up ${modelId} for which assistants? ${dim("(space toggles, enter confirms)")}`),
|
|
4111
4330
|
options,
|
|
4112
4331
|
initialValues: initial,
|
|
4113
4332
|
required: false,
|
|
@@ -4316,6 +4535,12 @@ const FLAGS = {
|
|
|
4316
4535
|
hint: "assistant ids",
|
|
4317
4536
|
text: `comma list of: ${IDS.join(", ")} (skips the picker)`
|
|
4318
4537
|
},
|
|
4538
|
+
provider: {
|
|
4539
|
+
type: "string",
|
|
4540
|
+
usage: "--provider <id>",
|
|
4541
|
+
hint: "gateway serving Apex",
|
|
4542
|
+
text: `${PROVIDER_IDS.join(" or ")}; defaults to the one whose key is set, else vercel (skips the question)`
|
|
4543
|
+
},
|
|
4319
4544
|
"no-interactive": {
|
|
4320
4545
|
type: "boolean",
|
|
4321
4546
|
usage: "--no-interactive",
|
|
@@ -4360,6 +4585,7 @@ const COMMANDS = {
|
|
|
4360
4585
|
summary: "configure assistants",
|
|
4361
4586
|
flags: [
|
|
4362
4587
|
"assistants",
|
|
4588
|
+
"provider",
|
|
4363
4589
|
"no-interactive",
|
|
4364
4590
|
"apply",
|
|
4365
4591
|
"no-diff",
|
|
@@ -4368,9 +4594,13 @@ const COMMANDS = {
|
|
|
4368
4594
|
]
|
|
4369
4595
|
},
|
|
4370
4596
|
detect: {
|
|
4371
|
-
args: "[--json]",
|
|
4597
|
+
args: "[--provider <id>] [--json]",
|
|
4372
4598
|
summary: "show what Apex CLI can see on this machine",
|
|
4373
|
-
flags: [
|
|
4599
|
+
flags: [
|
|
4600
|
+
"provider",
|
|
4601
|
+
"json",
|
|
4602
|
+
"help"
|
|
4603
|
+
]
|
|
4374
4604
|
},
|
|
4375
4605
|
undo: {
|
|
4376
4606
|
args: "[--list] [options]",
|
|
@@ -4385,7 +4615,7 @@ const COMMANDS = {
|
|
|
4385
4615
|
]
|
|
4386
4616
|
},
|
|
4387
4617
|
run: {
|
|
4388
|
-
args:
|
|
4618
|
+
args: `[--provider <id>] <${RUNNABLE.join("|")}> [-- <args>]`,
|
|
4389
4619
|
summary: "launch an assistant with the gateway set",
|
|
4390
4620
|
flags: []
|
|
4391
4621
|
},
|
|
@@ -4449,12 +4679,13 @@ const exampleRows = [
|
|
|
4449
4679
|
["apex init", "pick assistants, review, confirm"],
|
|
4450
4680
|
["apex init --assistants codex,pi", "preview two tools (agent and CI friendly)"],
|
|
4451
4681
|
["apex init --assistants codex,pi --apply", "write those two without asking"],
|
|
4682
|
+
["apex init --provider callstack", "use the Callstack portal instead of Vercel AI Gateway"],
|
|
4452
4683
|
["apex undo", "preview the reversal"],
|
|
4453
4684
|
["apex undo --apply", "reverse the last setup without asking"],
|
|
4454
4685
|
["apex detect --json", "machine-readable inventory"]
|
|
4455
4686
|
];
|
|
4456
4687
|
const environmentRows = [
|
|
4457
|
-
[
|
|
4688
|
+
...Object.values(PROVIDERS).map((provider) => [provider.envVar, `${provider.keyName}, needed by apex run and by every assistant you configure for ${provider.name}`]),
|
|
4458
4689
|
["Config directories", "XDG_CONFIG_HOME, CODEX_HOME, CLAUDE_CONFIG_DIR, PI_CODING_AGENT_DIR"],
|
|
4459
4690
|
["Undo journal", "APEX_STATE_DIR, XDG_STATE_HOME (default ~/.local/state/apex)"]
|
|
4460
4691
|
];
|
|
@@ -4503,7 +4734,7 @@ function helpText() {
|
|
|
4503
4734
|
""
|
|
4504
4735
|
];
|
|
4505
4736
|
return [
|
|
4506
|
-
...wrap(`Apex CLI: point your coding assistants at ${
|
|
4737
|
+
...wrap(`Apex CLI: point your coding assistants at Apex via ${Object.values(PROVIDERS).map((provider) => provider.name).join(" or the ")}`, width$1).map((line) => bold(model(line))),
|
|
4507
4738
|
"",
|
|
4508
4739
|
...section("Usage", usageRows.map(([lead, text]) => [
|
|
4509
4740
|
lead,
|
|
@@ -4543,9 +4774,11 @@ function readFlags(rest, command) {
|
|
|
4543
4774
|
const selected = values.assistants === void 0 ? null : [...new Set(values.assistants.split(",").map((id) => id.trim()))];
|
|
4544
4775
|
if (selected?.includes("")) throw new Error("--assistants needs at least one id.");
|
|
4545
4776
|
if (selected?.some((id) => !IDS.includes(id))) throw new Error(`Unknown assistant in --assistants. Choose from: ${IDS.join(", ")}`);
|
|
4777
|
+
if (values.provider !== void 0 && !PROVIDER_IDS.includes(values.provider)) throw new Error(`Unknown --provider. Choose from: ${PROVIDER_IDS.join(", ")}`);
|
|
4546
4778
|
const json = Boolean(values.json);
|
|
4547
4779
|
return {
|
|
4548
4780
|
selected,
|
|
4781
|
+
provider: values.provider === void 0 ? null : PROVIDERS[values.provider],
|
|
4549
4782
|
showDiff: !values["no-diff"],
|
|
4550
4783
|
json,
|
|
4551
4784
|
help: Boolean(values.help),
|
|
@@ -4556,7 +4789,7 @@ function readFlags(rest, command) {
|
|
|
4556
4789
|
})
|
|
4557
4790
|
};
|
|
4558
4791
|
}
|
|
4559
|
-
async function planAll(assistants, options) {
|
|
4792
|
+
async function planAll(assistants, options, provider) {
|
|
4560
4793
|
return Promise.all(assistants.map(async (assistant) => {
|
|
4561
4794
|
const base = {
|
|
4562
4795
|
id: assistant.id,
|
|
@@ -4569,7 +4802,7 @@ async function planAll(assistants, options) {
|
|
|
4569
4802
|
steps: []
|
|
4570
4803
|
};
|
|
4571
4804
|
try {
|
|
4572
|
-
base.files = (await planAssistant(assistant)).map((change) => describeFile(change, options));
|
|
4805
|
+
base.files = (await planAssistant(assistant, provider)).map((change) => describeFile(change, options));
|
|
4573
4806
|
base.steps = base.files.flatMap((file) => file.change.steps ?? []);
|
|
4574
4807
|
} catch (error) {
|
|
4575
4808
|
base.error = error.message;
|
|
@@ -4577,7 +4810,7 @@ async function planAll(assistants, options) {
|
|
|
4577
4810
|
return base;
|
|
4578
4811
|
}));
|
|
4579
4812
|
}
|
|
4580
|
-
const token = () => process.env.
|
|
4813
|
+
const token = (provider) => process.env[provider.envVar]?.trim() || void 0;
|
|
4581
4814
|
const stamp = (iso) => iso.replace("T", " ").replace(/\.\d{3}Z$/, " UTC");
|
|
4582
4815
|
const pendingOf = (entry) => entry.files.filter((file) => file.status !== "unchanged");
|
|
4583
4816
|
async function applyAll(items, apply) {
|
|
@@ -4610,6 +4843,11 @@ const jsonAssistant = (entry, secret) => ({
|
|
|
4610
4843
|
...entry.steps.length ? { steps: entry.steps } : {},
|
|
4611
4844
|
files: entry.files.map((file) => jsonFile(file, secret))
|
|
4612
4845
|
});
|
|
4846
|
+
const providerOptions = () => Object.values(PROVIDERS).map((provider) => ({
|
|
4847
|
+
value: provider.id,
|
|
4848
|
+
label: provider.name,
|
|
4849
|
+
hint: `${provider.model}, key in ${provider.envVar}${token(provider) ? " (set)" : ""}`
|
|
4850
|
+
}));
|
|
4613
4851
|
function pickerOptions(entries) {
|
|
4614
4852
|
return entries.map((entry) => {
|
|
4615
4853
|
const pending = pendingOf(entry).length;
|
|
@@ -4626,24 +4864,29 @@ async function commandInit(rest) {
|
|
|
4626
4864
|
printHelp();
|
|
4627
4865
|
return;
|
|
4628
4866
|
}
|
|
4629
|
-
const
|
|
4867
|
+
const journalFile = journalPath();
|
|
4868
|
+
if (flags.mode !== "preview") await readJournal(journalFile);
|
|
4869
|
+
const batch = randomUUID();
|
|
4870
|
+
const asking = !flags.json && flags.mode === "prompt";
|
|
4871
|
+
let provider = flags.provider ?? defaultProvider();
|
|
4872
|
+
if (!flags.json) intro("Apex CLI · Configure Apex for your favorite harness", MODE_NOTE[flags.mode]);
|
|
4873
|
+
if (asking && !flags.provider) {
|
|
4874
|
+
const picked = await selectProvider(providerOptions(), provider.id);
|
|
4875
|
+
if (picked === false) return;
|
|
4876
|
+
provider = PROVIDERS[picked];
|
|
4877
|
+
}
|
|
4878
|
+
const secret = token(provider);
|
|
4630
4879
|
const options = {
|
|
4631
4880
|
secret,
|
|
4632
4881
|
showDiff: flags.showDiff && !flags.json
|
|
4633
4882
|
};
|
|
4634
|
-
const
|
|
4635
|
-
if (flags.mode !== "preview") await readJournal(journalFile);
|
|
4636
|
-
const batch = randomUUID();
|
|
4637
|
-
const entries = await planAll(await detect(), options);
|
|
4883
|
+
const entries = await planAll(await detect(), options, provider);
|
|
4638
4884
|
let ids = flags.selected ?? entries.filter((entry) => entry.detected).map((entry) => entry.id);
|
|
4639
|
-
if (!flags.
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
if (picked === false) return;
|
|
4645
|
-
ids = picked;
|
|
4646
|
-
}
|
|
4885
|
+
if (asking && !flags.selected) {
|
|
4886
|
+
const defaults = entries.filter((entry) => entry.detected && !entry.manual && !entry.error && pendingOf(entry).length).map((entry) => entry.id);
|
|
4887
|
+
const picked = await selectAssistants(pickerOptions(entries), defaults, provider.model);
|
|
4888
|
+
if (picked === false) return;
|
|
4889
|
+
ids = picked;
|
|
4647
4890
|
}
|
|
4648
4891
|
const chosen = ids.map((id) => entries.find((entry) => entry.id === id));
|
|
4649
4892
|
const blocked = chosen.filter((entry) => entry.error);
|
|
@@ -4664,8 +4907,9 @@ async function commandInit(rest) {
|
|
|
4664
4907
|
console.log(JSON.stringify({
|
|
4665
4908
|
command: "init",
|
|
4666
4909
|
mode: flags.mode,
|
|
4667
|
-
|
|
4668
|
-
|
|
4910
|
+
provider: provider.id,
|
|
4911
|
+
model: provider.model,
|
|
4912
|
+
endpoint: provider.baseUrl,
|
|
4669
4913
|
applied: applied.length,
|
|
4670
4914
|
appliedPaths: applied,
|
|
4671
4915
|
...failure ? { error: failure.message } : {},
|
|
@@ -4677,7 +4921,7 @@ async function commandInit(rest) {
|
|
|
4677
4921
|
assistants: chosen.map((entry) => jsonAssistant(entry, secret)),
|
|
4678
4922
|
journal: journalFile,
|
|
4679
4923
|
undo: `${APEX} undo`,
|
|
4680
|
-
envVar:
|
|
4924
|
+
envVar: provider.envVar,
|
|
4681
4925
|
nextSteps: active.filter((entry) => RUNNABLE.includes(entry.id)).map((entry) => `${APEX} run ${entry.id}`)
|
|
4682
4926
|
}, null, 2));
|
|
4683
4927
|
if (blocked.length || failure) process.exitCode = 1;
|
|
@@ -4687,7 +4931,10 @@ async function commandInit(rest) {
|
|
|
4687
4931
|
outro(`No assistant selected, so nothing was written. Pick one with --assistants or run ${APEX} init interactively.`);
|
|
4688
4932
|
return;
|
|
4689
4933
|
}
|
|
4690
|
-
if (flags.mode !== "prompt")
|
|
4934
|
+
if (flags.mode !== "prompt") {
|
|
4935
|
+
prose(`${gray("gateway:")} ${provider.name}`);
|
|
4936
|
+
prose(`${gray("setup for:")} ${chosen.map((entry) => entry.name + (entry.detected ? "" : " (not detected)")).join(", ")}`);
|
|
4937
|
+
}
|
|
4691
4938
|
if (blocked.length) {
|
|
4692
4939
|
plain("");
|
|
4693
4940
|
for (const entry of blocked) error(`${entry.name}: ${shortPath(entry.error)}`);
|
|
@@ -4715,23 +4962,24 @@ async function commandInit(rest) {
|
|
|
4715
4962
|
}
|
|
4716
4963
|
const apex = APEX !== "apex" && flags.mode === "prompt" && await installApex() ? "apex" : APEX;
|
|
4717
4964
|
for (const entry of active.filter((entry) => entry.steps.length)) section(`Finish setting up ${entry.name}`, entry.steps);
|
|
4718
|
-
for (const entry of manual) section(`Manual setup for ${entry.name}: Apex CLI writes nothing`,
|
|
4965
|
+
for (const entry of manual) section(`Manual setup for ${entry.name}: Apex CLI writes nothing`, manualSteps(entry.id, provider));
|
|
4719
4966
|
section("Environment", [
|
|
4720
|
-
...secret ? [] : [
|
|
4721
|
-
secret ? `${green("✓")}
|
|
4967
|
+
...secret ? [] : [`export ${provider.envVar}=<${provider.keyName.replace(/^your /, "")}>`],
|
|
4968
|
+
secret ? `${green("✓")} ${provider.envVar} is set in this shell` : `${yellow("!")} ${provider.envVar} is not set here yet`,
|
|
4969
|
+
...!secret && provider.keysUrl ? [`Create a key at ${link(provider.keysUrl)}`] : [],
|
|
4722
4970
|
dim("Apex CLI never reads, stores or logs the key itself.")
|
|
4723
4971
|
]);
|
|
4724
4972
|
const runnable = active.map((entry) => entry.id).filter((id) => RUNNABLE.includes(id));
|
|
4725
4973
|
const rows = runnable.map((id) => ({
|
|
4726
4974
|
command: `${apex} run ${id}`,
|
|
4727
|
-
expansion: runExpansion(id)
|
|
4975
|
+
expansion: runExpansion(id, provider)
|
|
4728
4976
|
}));
|
|
4729
4977
|
const commandWidth = columnWidth(rows.map((row) => row.command));
|
|
4730
|
-
section(runnable.length ? `Use these commands to run ${
|
|
4978
|
+
section(runnable.length ? `Use these commands to run ${provider.model} with your selected harnesses:` : `Use ${provider.model} with your assistant:`, [
|
|
4731
4979
|
...rows.flatMap((row) => wrap(row.expansion, width() - 3 - commandWidth).map((part, index) => `${pad(index ? "" : row.command, commandWidth)}${dim(part)}`)),
|
|
4732
4980
|
"",
|
|
4733
|
-
`...or pick "${
|
|
4734
|
-
`For more instructions, visit: ${link(
|
|
4981
|
+
`...or pick "${provider.model}" from the UI when setting up manually.`,
|
|
4982
|
+
`For more instructions, visit: ${link(provider.guideUrl)}`,
|
|
4735
4983
|
...applied ? ["", `If you want to undo the changes, run ${bold(`${apex} undo`)}`] : [],
|
|
4736
4984
|
...apex === "apex" ? [] : ["", dim("For the short apex command: npm install -g @callstack/apex")]
|
|
4737
4985
|
]);
|
|
@@ -4742,16 +4990,17 @@ async function commandDetect(rest) {
|
|
|
4742
4990
|
printHelp();
|
|
4743
4991
|
return;
|
|
4744
4992
|
}
|
|
4745
|
-
const
|
|
4993
|
+
const provider = flags.provider ?? defaultProvider();
|
|
4994
|
+
const secret = token(provider);
|
|
4746
4995
|
const entries = await planAll(await detect(), {
|
|
4747
4996
|
secret,
|
|
4748
4997
|
showDiff: false
|
|
4749
|
-
});
|
|
4998
|
+
}, provider);
|
|
4750
4999
|
if (flags.json) {
|
|
4751
5000
|
console.log(JSON.stringify(entries.map((entry) => jsonAssistant(entry, secret)), null, 2));
|
|
4752
5001
|
return;
|
|
4753
5002
|
}
|
|
4754
|
-
intro(
|
|
5003
|
+
intro(`Apex CLI · What this machine has for ${provider.name}`, "Read only: nothing is created, edited or removed.");
|
|
4755
5004
|
const rows = entries.map((entry) => {
|
|
4756
5005
|
const pending = pendingOf(entry).length;
|
|
4757
5006
|
return {
|
|
@@ -4777,7 +5026,7 @@ async function commandUndo(rest) {
|
|
|
4777
5026
|
printHelp();
|
|
4778
5027
|
return;
|
|
4779
5028
|
}
|
|
4780
|
-
const secret = token();
|
|
5029
|
+
const secret = token(defaultProvider());
|
|
4781
5030
|
const options = {
|
|
4782
5031
|
secret,
|
|
4783
5032
|
showDiff: flags.showDiff && !flags.json
|
|
@@ -4875,10 +5124,33 @@ async function commandUndo(rest) {
|
|
|
4875
5124
|
}
|
|
4876
5125
|
})).applied) outro("Undone. Configs are back to how they were. Restart any open assistant to reload them.");
|
|
4877
5126
|
}
|
|
5127
|
+
function takeProvider(args) {
|
|
5128
|
+
const [first, second] = args;
|
|
5129
|
+
if (first === "--provider") return {
|
|
5130
|
+
value: second ?? "",
|
|
5131
|
+
rest: args.slice(2)
|
|
5132
|
+
};
|
|
5133
|
+
if (first?.startsWith("--provider=")) return {
|
|
5134
|
+
value: first.slice(11),
|
|
5135
|
+
rest: args.slice(1)
|
|
5136
|
+
};
|
|
5137
|
+
return {
|
|
5138
|
+
value: null,
|
|
5139
|
+
rest: args
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
4878
5142
|
async function commandRun(rest) {
|
|
4879
|
-
const
|
|
5143
|
+
const before = takeProvider(rest);
|
|
5144
|
+
const [id, ...after] = before.rest;
|
|
4880
5145
|
if (!RUNNABLE.includes(id)) throw new Error(`apex run needs one of: ${RUNNABLE.join(", ")}. See ${APEX} --help.`);
|
|
4881
|
-
const
|
|
5146
|
+
const behind = before.value === null ? takeProvider(after) : {
|
|
5147
|
+
value: null,
|
|
5148
|
+
rest: after
|
|
5149
|
+
};
|
|
5150
|
+
const chosen = before.value ?? behind.value;
|
|
5151
|
+
if (chosen !== null && !PROVIDER_IDS.includes(chosen)) throw new Error(`Unknown --provider. Choose from: ${PROVIDER_IDS.join(", ")}`);
|
|
5152
|
+
const passed = behind.rest;
|
|
5153
|
+
const options = launchOptions(id, process.env, chosen === null ? defaultProvider() : PROVIDERS[chosen]);
|
|
4882
5154
|
const binary = await executable(id);
|
|
4883
5155
|
if (!binary) throw new Error(`${id} was not found on PATH. Install it first, then run ${APEX} init.`);
|
|
4884
5156
|
if (process.platform === "win32" && /\.(cmd|bat)$/i.test(binary)) throw new Error("Windows .cmd/.bat launchers are not executed through a shell. Use WSL or launch the configured assistant directly.");
|
|
@@ -4901,7 +5173,8 @@ const completionsFor = (command) => COMMANDS[command].flags.map((flag) => ({
|
|
|
4901
5173
|
long: `--${flag}`,
|
|
4902
5174
|
short: FLAGS[flag].short ? `-${FLAGS[flag].short}` : null,
|
|
4903
5175
|
hint: FLAGS[flag].hint,
|
|
4904
|
-
...command === "init" && flag === "assistants" ? { values: IDS } : {}
|
|
5176
|
+
...command === "init" && flag === "assistants" ? { values: IDS } : {},
|
|
5177
|
+
...flag === "provider" ? { values: PROVIDER_IDS } : {}
|
|
4905
5178
|
}));
|
|
4906
5179
|
const spellings = (entry) => [entry.long, entry.short].filter(Boolean);
|
|
4907
5180
|
function completionScript(shell) {
|
|
@@ -4909,15 +5182,18 @@ function completionScript(shell) {
|
|
|
4909
5182
|
const words = (list) => list.join(" ");
|
|
4910
5183
|
if (shell === "zsh") return `#compdef apex
|
|
4911
5184
|
_apex() {
|
|
4912
|
-
local -a commands assistants runnable${taking.length ? " " : ""}${words(taking.map((name) => `${name}_flags`))}
|
|
5185
|
+
local -a commands assistants providers runnable${taking.length ? " " : ""}${words(taking.map((name) => `${name}_flags`))}
|
|
4913
5186
|
commands=(${words([...Object.entries(COMMANDS).map(([name, command]) => `'${name}:${command.summary}'`), ...GLOBALS.map(([flag, text]) => `'${flag}:${text}'`)])})
|
|
4914
5187
|
assistants=(${words(IDS)})
|
|
5188
|
+
providers=(${words(PROVIDER_IDS)})
|
|
4915
5189
|
runnable=(${words(RUNNABLE)})
|
|
4916
5190
|
${taking.map((name) => ` ${name}_flags=(${words(completionsFor(name).flatMap((entry) => spellings(entry).map((word) => `'${word}:${entry.hint}'`)))})`).join("\n")}
|
|
4917
5191
|
if (( CURRENT == 2 )); then
|
|
4918
5192
|
_describe -t commands 'apex command' commands
|
|
4919
5193
|
elif [[ "\${words[CURRENT - 1]}" == --assistants ]]; then
|
|
4920
5194
|
_describe -t assistants 'assistant' assistants
|
|
5195
|
+
elif [[ "\${words[CURRENT - 1]}" == --provider ]]; then
|
|
5196
|
+
_describe -t providers 'gateway' providers
|
|
4921
5197
|
else
|
|
4922
5198
|
case "\${words[2]}" in
|
|
4923
5199
|
${taking.map((name) => ` ${name}) _describe -t flags 'option' ${name}_flags ;;`).join("\n")}
|
|
@@ -4932,6 +5208,7 @@ if [[ "\${funcstack[1]}" == _apex ]]; then _apex "$@"; else compdef _apex apex;
|
|
|
4932
5208
|
if (shell === "bash") return `_apex_completions() {
|
|
4933
5209
|
local sub="\${COMP_WORDS[1]}" prev="\${COMP_WORDS[COMP_CWORD - 1]}" current="\${COMP_WORDS[COMP_CWORD]}"
|
|
4934
5210
|
if [[ "$prev" == --assistants ]]; then COMPREPLY=( $(compgen -W "${words(IDS)}" -- "$current") ); return; fi
|
|
5211
|
+
if [[ "$prev" == --provider ]]; then COMPREPLY=( $(compgen -W "${words(PROVIDER_IDS)}" -- "$current") ); return; fi
|
|
4935
5212
|
if (( COMP_CWORD == 1 )); then
|
|
4936
5213
|
COMPREPLY=( $(compgen -W "${words([...Object.keys(COMMANDS), ...GLOBALS.map(([flag]) => flag)])}" -- "$current") )
|
|
4937
5214
|
return
|
|
@@ -4950,6 +5227,12 @@ complete -F _apex_completions apex
|
|
|
4950
5227
|
...GLOBALS.map(([flag, hint]) => `complete -c apex -f -n "__fish_use_subcommand" -l ${flag.slice(2)} -d '${hint}'`),
|
|
4951
5228
|
...taking.flatMap((name) => completionsFor(name).map((entry) => fish(`__fish_seen_subcommand_from ${name}`, entry))),
|
|
4952
5229
|
...RUNNABLE.map((id) => `complete -c apex -f -n "__fish_seen_subcommand_from run" -a ${id} -d 'assistant'`),
|
|
5230
|
+
fish("__fish_seen_subcommand_from run", {
|
|
5231
|
+
long: "--provider",
|
|
5232
|
+
short: null,
|
|
5233
|
+
hint: FLAGS.provider.hint,
|
|
5234
|
+
values: PROVIDER_IDS
|
|
5235
|
+
}),
|
|
4953
5236
|
...SHELLS.map((name) => `complete -c apex -f -n "__fish_seen_subcommand_from completion" -a ${name} -d 'shell'`)
|
|
4954
5237
|
].join("\n") + "\n";
|
|
4955
5238
|
}
|