token-goat 2.6.35 → 2.8.0
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 +35 -7
- package/SECURITY.md +47 -16
- package/dist/{token-goat-chunk-I2KCEGIP.mjs → token-goat-chunk-2F6TFBZE.mjs} +1355 -408
- package/dist/token-goat-chunk-324QOJYZ.mjs +91 -0
- package/dist/{token-goat-chunk-K7W3P2TJ.mjs → token-goat-chunk-44Y77VHR.mjs} +425 -39
- package/dist/{token-goat-chunk-UIZVX3HN.mjs → token-goat-chunk-4KZILRZN.mjs} +2 -2
- package/dist/token-goat-chunk-5CVKO3DA.mjs +185 -0
- package/dist/token-goat-chunk-A62K4XW2.mjs +23 -0
- package/dist/{token-goat-chunk-SIHYQCTM.mjs → token-goat-chunk-AO6MFFTW.mjs} +331 -13
- package/dist/{token-goat-chunk-DRAIYVUI.mjs → token-goat-chunk-FBGBTICM.mjs} +4 -4
- package/dist/{token-goat-chunk-YF67EWRH.mjs → token-goat-chunk-J35AKWEQ.mjs} +5 -5
- package/dist/{token-goat-hook-chunk-4POU6OHK.mjs → token-goat-chunk-LVCBDJVE.mjs} +318 -51
- package/dist/token-goat-chunk-R4SR7MQY.mjs +486 -0
- package/dist/{token-goat-chunk-D5IZEGN2.mjs → token-goat-chunk-SRAR6DOK.mjs} +144 -147
- package/dist/{token-goat-hook-chunk-NIPXIAPA.mjs → token-goat-chunk-TUPJRK7R.mjs} +1 -1
- package/dist/{token-goat-chunk-HW4VUKJ5.mjs → token-goat-chunk-VXSYZGBA.mjs} +589 -141
- package/dist/{token-goat-chunk-DG53MVNJ.mjs → token-goat-chunk-WN5T5EW5.mjs} +212 -212
- package/dist/token-goat-hook.mjs +7 -7
- package/dist/token-goat.core.mjs +5 -5
- package/package.json +18 -15
- package/scripts/install-git-hooks.mjs +55 -0
- package/dist/token-goat-chunk-DQIT5JIF.mjs +0 -13659
- package/dist/token-goat-chunk-Y2NH6DGZ.mjs +0 -10048
- package/dist/token-goat-hook-chunk-2O7P4Z6Q.mjs +0 -6419
- package/dist/token-goat-hook-chunk-3AAH72SO.mjs +0 -15970
- package/dist/token-goat-hook-chunk-3QYSN4QV.mjs +0 -14764
- package/dist/token-goat-hook-chunk-BUOCULAM.mjs +0 -29
- package/dist/token-goat-hook-chunk-CRBMPT74.mjs +0 -900
- package/dist/token-goat-hook-chunk-D6UJEFHX.mjs +0 -153
- package/dist/token-goat-hook-chunk-J4HKWUWZ.mjs +0 -23
- package/dist/token-goat-hook-chunk-NXVT4F3S.mjs +0 -10406
- package/dist/token-goat-hook-chunk-RFRLWOQH.mjs +0 -11
- package/dist/token-goat-hook-chunk-VU6VGZBM.mjs +0 -706
- package/dist/token-goat-hook-chunk-XM4W3WCO.mjs +0 -18144
- package/dist/token-goat-hook-chunk-XUMIVYEN.mjs +0 -109
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
function resolveVersion() {
|
|
10
10
|
if (true) {
|
|
11
|
-
return "2.
|
|
11
|
+
return "2.8.0";
|
|
12
12
|
}
|
|
13
13
|
const require2 = createRequire(import.meta.url);
|
|
14
14
|
const pkg = require2("../package.json");
|
|
@@ -418,14 +418,14 @@ function ensureDirSync(dir) {
|
|
|
418
418
|
}
|
|
419
419
|
function withRetryOnLock(fn) {
|
|
420
420
|
let lastErr;
|
|
421
|
-
for (let
|
|
421
|
+
for (let attempt2 = 1; attempt2 <= 5; attempt2++) {
|
|
422
422
|
try {
|
|
423
423
|
fn();
|
|
424
424
|
return;
|
|
425
425
|
} catch (err) {
|
|
426
426
|
lastErr = err;
|
|
427
|
-
if (!isRetryable(err) ||
|
|
428
|
-
sleepSync(50 *
|
|
427
|
+
if (!isRetryable(err) || attempt2 === 5) throw err;
|
|
428
|
+
sleepSync(50 * attempt2);
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
throw lastErr;
|
|
@@ -559,7 +559,7 @@ function withFileLock(lockPath, fn, opts = {}) {
|
|
|
559
559
|
const staleMs = opts.staleMs ?? LOCK_STALE_MS;
|
|
560
560
|
const token = `${process.pid}:${process.hrtime.bigint().toString()}`;
|
|
561
561
|
const deadline = Date.now() + waitMs;
|
|
562
|
-
let
|
|
562
|
+
let attempt2 = 0;
|
|
563
563
|
for (; ; ) {
|
|
564
564
|
try {
|
|
565
565
|
writeFileSync(lockPath, token, { flag: "wx" });
|
|
@@ -582,7 +582,7 @@ function withFileLock(lockPath, fn, opts = {}) {
|
|
|
582
582
|
continue;
|
|
583
583
|
}
|
|
584
584
|
if (Date.now() >= deadline) return void 0;
|
|
585
|
-
sleepSync(Math.min(20 * ++
|
|
585
|
+
sleepSync(Math.min(20 * ++attempt2, 200));
|
|
586
586
|
}
|
|
587
587
|
const heartbeat = startHeartbeat(lockPath, token, staleMs);
|
|
588
588
|
try {
|
|
@@ -770,6 +770,9 @@ function countContentLines(content) {
|
|
|
770
770
|
const n = content.split("\n").length;
|
|
771
771
|
return content.endsWith("\n") ? n - 1 : n;
|
|
772
772
|
}
|
|
773
|
+
function pushAll(target, items) {
|
|
774
|
+
for (const item of items) target.push(item);
|
|
775
|
+
}
|
|
773
776
|
function escapeRegExp(s) {
|
|
774
777
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
775
778
|
}
|
|
@@ -2449,7 +2452,6 @@ var ENV_KEYS2 = [
|
|
|
2449
2452
|
"TOKEN_GOAT_OVERFLOW_MAX_TOKENS",
|
|
2450
2453
|
"TOKEN_GOAT_HINT_JSON_SIDECAR",
|
|
2451
2454
|
"TOKEN_GOAT_LARGE_READ_BYTES",
|
|
2452
|
-
"TOKEN_GOAT_CURATOR",
|
|
2453
2455
|
"TOKEN_GOAT_HINT_BUDGET",
|
|
2454
2456
|
"TOKEN_GOAT_HOOK_WATCHDOG_MS",
|
|
2455
2457
|
"TOKEN_GOAT_WEB_COMPRESS",
|
|
@@ -2510,8 +2512,19 @@ var _lastProjectConfigParseError = null;
|
|
|
2510
2512
|
function getLastProjectConfigParseError() {
|
|
2511
2513
|
return _lastProjectConfigParseError;
|
|
2512
2514
|
}
|
|
2513
|
-
var PROJECT_LOCKED_SECTIONS = [
|
|
2514
|
-
|
|
2515
|
+
var PROJECT_LOCKED_SECTIONS = [
|
|
2516
|
+
"injection",
|
|
2517
|
+
"webfetch",
|
|
2518
|
+
"gdrive",
|
|
2519
|
+
"mcp",
|
|
2520
|
+
"network",
|
|
2521
|
+
"screenshot"
|
|
2522
|
+
];
|
|
2523
|
+
var PROJECT_LOCKED_KEYS = [
|
|
2524
|
+
"image_shrink.max_image_pixels",
|
|
2525
|
+
"indexing.cross_project_symbols",
|
|
2526
|
+
"worker.blocked_roots"
|
|
2527
|
+
];
|
|
2515
2528
|
var _lastProjectConfigLockedKeys = [];
|
|
2516
2529
|
function stripLockedProjectKeys(projectRaw) {
|
|
2517
2530
|
const cleaned = {};
|
|
@@ -2642,10 +2655,12 @@ function resolveConfigKeyLayer(key, effectiveValue, cfg, projectInfo) {
|
|
|
2642
2655
|
if (rawValueEquals(rawValue, effectiveValue)) return { layer: "project", path: projectInfo.path };
|
|
2643
2656
|
return { layer: "project-invalid", path: projectInfo.path, rawValue, effectiveValue, reason: rejectionReason(key, rawValue, effectiveValue, cfg) };
|
|
2644
2657
|
}
|
|
2658
|
+
function readConfigSource(p) {
|
|
2659
|
+
return decodeSource(fs5.readFileSync(p));
|
|
2660
|
+
}
|
|
2645
2661
|
function readConfigToml(p) {
|
|
2646
2662
|
try {
|
|
2647
|
-
|
|
2648
|
-
return { raw: parse(text), parseError: null };
|
|
2663
|
+
return { raw: parse(readConfigSource(p)), parseError: null };
|
|
2649
2664
|
} catch (e) {
|
|
2650
2665
|
const code = e.code;
|
|
2651
2666
|
if (code === "ENOENT") return { raw: {}, parseError: null };
|
|
@@ -2654,7 +2669,7 @@ function readConfigToml(p) {
|
|
|
2654
2669
|
}
|
|
2655
2670
|
function readConfigText(p) {
|
|
2656
2671
|
try {
|
|
2657
|
-
return { text:
|
|
2672
|
+
return { text: readConfigSource(p), readError: null };
|
|
2658
2673
|
} catch (e) {
|
|
2659
2674
|
const code = e.code;
|
|
2660
2675
|
if (code === "ENOENT") return { text: null, readError: null };
|
|
@@ -2696,11 +2711,11 @@ function isAutoTriggerMultiplierExplicit() {
|
|
|
2696
2711
|
return ca_raw["auto_trigger_multiplier"] !== void 0;
|
|
2697
2712
|
};
|
|
2698
2713
|
try {
|
|
2699
|
-
if (setsMultiplier(
|
|
2714
|
+
if (setsMultiplier(readConfigSource(configPath()))) return true;
|
|
2700
2715
|
} catch {
|
|
2701
2716
|
}
|
|
2702
2717
|
try {
|
|
2703
|
-
return setsMultiplier(
|
|
2718
|
+
return setsMultiplier(readConfigSource(projectConfigPath(resolveConfigProjectRoot())));
|
|
2704
2719
|
} catch {
|
|
2705
2720
|
return false;
|
|
2706
2721
|
}
|
|
@@ -3685,17 +3700,21 @@ function isInsideStringLiteral(line, index, from = 0) {
|
|
|
3685
3700
|
}
|
|
3686
3701
|
return openQuote !== null;
|
|
3687
3702
|
}
|
|
3703
|
+
function nextBlockCommentOpen(line, from) {
|
|
3704
|
+
const lineCommentIdx = lineCommentStartIndex(line, ["//"], from);
|
|
3705
|
+
let open = line.indexOf("/*", from);
|
|
3706
|
+
while (open !== -1 && (isInsideStringLiteral(line, open, from) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3707
|
+
open = line.indexOf("/*", open + 1);
|
|
3708
|
+
}
|
|
3709
|
+
return open;
|
|
3710
|
+
}
|
|
3688
3711
|
function stripBlockCommentSpan(line, inComment) {
|
|
3689
3712
|
let code = "";
|
|
3690
3713
|
let j = 0;
|
|
3691
3714
|
let comment = inComment;
|
|
3692
3715
|
while (j < line.length) {
|
|
3693
3716
|
if (!comment) {
|
|
3694
|
-
const
|
|
3695
|
-
let open = line.indexOf("/*", j);
|
|
3696
|
-
while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3697
|
-
open = line.indexOf("/*", open + 1);
|
|
3698
|
-
}
|
|
3717
|
+
const open = nextBlockCommentOpen(line, j);
|
|
3699
3718
|
if (open === -1) {
|
|
3700
3719
|
code += line.slice(j);
|
|
3701
3720
|
break;
|
|
@@ -3729,11 +3748,7 @@ function stripNestedBlockCommentSpan(line, depth) {
|
|
|
3729
3748
|
let d = depth;
|
|
3730
3749
|
while (j < line.length) {
|
|
3731
3750
|
if (d === 0) {
|
|
3732
|
-
const
|
|
3733
|
-
let open = line.indexOf("/*", j);
|
|
3734
|
-
while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3735
|
-
open = line.indexOf("/*", open + 1);
|
|
3736
|
-
}
|
|
3751
|
+
const open = nextBlockCommentOpen(line, j);
|
|
3737
3752
|
if (open === -1) {
|
|
3738
3753
|
code += line.slice(j);
|
|
3739
3754
|
break;
|
|
@@ -4179,6 +4194,7 @@ function propagateEndLinesToSymbols(symbols, sections) {
|
|
|
4179
4194
|
}
|
|
4180
4195
|
function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex, lineCommentPrefix, opts) {
|
|
4181
4196
|
const block = opts?.blockComment;
|
|
4197
|
+
const backtick = opts?.backtickQuote === true;
|
|
4182
4198
|
let depth = 0;
|
|
4183
4199
|
let quote = null;
|
|
4184
4200
|
for (let i = openBraceIndex; i < content.length; i++) {
|
|
@@ -4200,7 +4216,7 @@ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex
|
|
|
4200
4216
|
while (i < content.length && content[i] !== "\n") i++;
|
|
4201
4217
|
continue;
|
|
4202
4218
|
}
|
|
4203
|
-
if (ch === '"' || ch === "'") {
|
|
4219
|
+
if (ch === '"' || ch === "'" || backtick && ch === "`") {
|
|
4204
4220
|
quote = ch;
|
|
4205
4221
|
continue;
|
|
4206
4222
|
}
|
|
@@ -4438,11 +4454,328 @@ function redactIfDotenv(filePath, text) {
|
|
|
4438
4454
|
}
|
|
4439
4455
|
|
|
4440
4456
|
// src/db.ts
|
|
4457
|
+
import * as fs7 from "node:fs";
|
|
4458
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
4459
|
+
import * as path7 from "node:path";
|
|
4460
|
+
|
|
4461
|
+
// src/sqlite_driver.ts
|
|
4441
4462
|
import * as fs6 from "node:fs";
|
|
4442
4463
|
import { createRequire as createRequire2 } from "node:module";
|
|
4443
|
-
import * as path7 from "node:path";
|
|
4444
|
-
import Database from "better-sqlite3";
|
|
4445
4464
|
var _require = createRequire2(import.meta.url);
|
|
4465
|
+
function suppressSqliteExperimentalWarning() {
|
|
4466
|
+
const original = process.emit;
|
|
4467
|
+
let armed = true;
|
|
4468
|
+
const restore = () => {
|
|
4469
|
+
if (!armed) return;
|
|
4470
|
+
armed = false;
|
|
4471
|
+
process.emit = original;
|
|
4472
|
+
};
|
|
4473
|
+
process.emit = function patched(name, ...rest) {
|
|
4474
|
+
const data = rest[0];
|
|
4475
|
+
if (armed && name === "warning" && data instanceof Error && data.name === "ExperimentalWarning" && /sqlite/i.test(data.message)) {
|
|
4476
|
+
restore();
|
|
4477
|
+
return false;
|
|
4478
|
+
}
|
|
4479
|
+
return original.call(this, name, ...rest);
|
|
4480
|
+
};
|
|
4481
|
+
setImmediate(restore);
|
|
4482
|
+
return restore;
|
|
4483
|
+
}
|
|
4484
|
+
var restoreWarnings = suppressSqliteExperimentalWarning();
|
|
4485
|
+
var nodeSqlite;
|
|
4486
|
+
try {
|
|
4487
|
+
nodeSqlite = _require("node:sqlite");
|
|
4488
|
+
} catch (e) {
|
|
4489
|
+
restoreWarnings();
|
|
4490
|
+
throw e;
|
|
4491
|
+
}
|
|
4492
|
+
var { DatabaseSync } = nodeSqlite;
|
|
4493
|
+
var SQLITE_PRIMARY_CODES = [
|
|
4494
|
+
"SQLITE_OK",
|
|
4495
|
+
"SQLITE_ERROR",
|
|
4496
|
+
"SQLITE_INTERNAL",
|
|
4497
|
+
"SQLITE_PERM",
|
|
4498
|
+
"SQLITE_ABORT",
|
|
4499
|
+
"SQLITE_BUSY",
|
|
4500
|
+
"SQLITE_LOCKED",
|
|
4501
|
+
"SQLITE_NOMEM",
|
|
4502
|
+
"SQLITE_READONLY",
|
|
4503
|
+
"SQLITE_INTERRUPT",
|
|
4504
|
+
"SQLITE_IOERR",
|
|
4505
|
+
"SQLITE_CORRUPT",
|
|
4506
|
+
"SQLITE_NOTFOUND",
|
|
4507
|
+
"SQLITE_FULL",
|
|
4508
|
+
"SQLITE_CANTOPEN",
|
|
4509
|
+
"SQLITE_PROTOCOL",
|
|
4510
|
+
"SQLITE_EMPTY",
|
|
4511
|
+
"SQLITE_SCHEMA",
|
|
4512
|
+
"SQLITE_TOOBIG",
|
|
4513
|
+
"SQLITE_CONSTRAINT",
|
|
4514
|
+
"SQLITE_MISMATCH",
|
|
4515
|
+
"SQLITE_MISUSE",
|
|
4516
|
+
"SQLITE_NOLFS",
|
|
4517
|
+
"SQLITE_AUTH",
|
|
4518
|
+
"SQLITE_FORMAT",
|
|
4519
|
+
"SQLITE_RANGE",
|
|
4520
|
+
"SQLITE_NOTADB",
|
|
4521
|
+
"SQLITE_NOTICE",
|
|
4522
|
+
"SQLITE_WARNING"
|
|
4523
|
+
];
|
|
4524
|
+
var SQLITE_EXTENDED_SUFFIXES = {
|
|
4525
|
+
SQLITE_OK: ["LOAD_PERMANENTLY", "SYMLINK"],
|
|
4526
|
+
SQLITE_ERROR: ["MISSING_COLLSEQ", "RETRY", "SNAPSHOT"],
|
|
4527
|
+
SQLITE_ABORT: [null, "ROLLBACK"],
|
|
4528
|
+
SQLITE_BUSY: ["RECOVERY", "SNAPSHOT", "TIMEOUT"],
|
|
4529
|
+
SQLITE_LOCKED: ["SHAREDCACHE", "VTAB"],
|
|
4530
|
+
SQLITE_READONLY: ["RECOVERY", "CANTLOCK", "ROLLBACK", "DBMOVED", "CANTINIT", "DIRECTORY"],
|
|
4531
|
+
SQLITE_IOERR: [
|
|
4532
|
+
"READ",
|
|
4533
|
+
"SHORT_READ",
|
|
4534
|
+
"WRITE",
|
|
4535
|
+
"FSYNC",
|
|
4536
|
+
"DIR_FSYNC",
|
|
4537
|
+
"TRUNCATE",
|
|
4538
|
+
"FSTAT",
|
|
4539
|
+
"UNLOCK",
|
|
4540
|
+
"RDLOCK",
|
|
4541
|
+
"DELETE",
|
|
4542
|
+
"BLOCKED",
|
|
4543
|
+
"NOMEM",
|
|
4544
|
+
"ACCESS",
|
|
4545
|
+
"CHECKRESERVEDLOCK",
|
|
4546
|
+
"LOCK",
|
|
4547
|
+
"CLOSE",
|
|
4548
|
+
"DIR_CLOSE",
|
|
4549
|
+
"SHMOPEN",
|
|
4550
|
+
"SHMSIZE",
|
|
4551
|
+
"SHMLOCK",
|
|
4552
|
+
"SHMMAP",
|
|
4553
|
+
"SEEK",
|
|
4554
|
+
"DELETE_NOENT",
|
|
4555
|
+
"MMAP",
|
|
4556
|
+
"GETTEMPPATH",
|
|
4557
|
+
"CONVPATH",
|
|
4558
|
+
"VNODE",
|
|
4559
|
+
"AUTH",
|
|
4560
|
+
"BEGIN_ATOMIC",
|
|
4561
|
+
"COMMIT_ATOMIC",
|
|
4562
|
+
"ROLLBACK_ATOMIC",
|
|
4563
|
+
"DATA",
|
|
4564
|
+
"CORRUPTFS",
|
|
4565
|
+
"IN_PAGE"
|
|
4566
|
+
],
|
|
4567
|
+
SQLITE_CORRUPT: ["VTAB", "SEQUENCE", "INDEX"],
|
|
4568
|
+
SQLITE_CANTOPEN: ["NOTEMPDIR", "ISDIR", "FULLPATH", "CONVPATH", "DIRTYWAL", "SYMLINK"],
|
|
4569
|
+
SQLITE_CONSTRAINT: [
|
|
4570
|
+
"CHECK",
|
|
4571
|
+
"COMMITHOOK",
|
|
4572
|
+
"FOREIGNKEY",
|
|
4573
|
+
"FUNCTION",
|
|
4574
|
+
"NOTNULL",
|
|
4575
|
+
"PRIMARYKEY",
|
|
4576
|
+
"TRIGGER",
|
|
4577
|
+
"UNIQUE",
|
|
4578
|
+
"VTAB",
|
|
4579
|
+
"ROWID",
|
|
4580
|
+
"PINNED",
|
|
4581
|
+
"DATATYPE"
|
|
4582
|
+
],
|
|
4583
|
+
SQLITE_AUTH: ["USER"],
|
|
4584
|
+
SQLITE_NOTICE: ["RECOVER_WAL", "RECOVER_ROLLBACK", "RBU"],
|
|
4585
|
+
SQLITE_WARNING: ["AUTOINDEX"]
|
|
4586
|
+
};
|
|
4587
|
+
function sqliteResultCodeName(errcode) {
|
|
4588
|
+
if (!Number.isInteger(errcode) || errcode < 0) return "ERR_SQLITE_ERROR";
|
|
4589
|
+
if (errcode === 100) return "SQLITE_ROW";
|
|
4590
|
+
if (errcode === 101) return "SQLITE_DONE";
|
|
4591
|
+
const primary = SQLITE_PRIMARY_CODES[errcode & 255];
|
|
4592
|
+
if (primary === void 0) return "ERR_SQLITE_ERROR";
|
|
4593
|
+
const subcode = errcode >> 8;
|
|
4594
|
+
if (subcode === 0) return primary;
|
|
4595
|
+
const suffix = SQLITE_EXTENDED_SUFFIXES[primary]?.[subcode - 1];
|
|
4596
|
+
return suffix === void 0 || suffix === null ? primary : `${primary}_${suffix}`;
|
|
4597
|
+
}
|
|
4598
|
+
function attempt(fn) {
|
|
4599
|
+
try {
|
|
4600
|
+
return fn();
|
|
4601
|
+
} catch (e) {
|
|
4602
|
+
const err = e;
|
|
4603
|
+
if (err.code === "ERR_SQLITE_ERROR" && typeof err.errcode === "number") {
|
|
4604
|
+
err.code = sqliteResultCodeName(err.errcode);
|
|
4605
|
+
}
|
|
4606
|
+
throw e;
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
var Statement = class {
|
|
4610
|
+
#stmt;
|
|
4611
|
+
#pluck = false;
|
|
4612
|
+
constructor(stmt) {
|
|
4613
|
+
this.#stmt = stmt;
|
|
4614
|
+
}
|
|
4615
|
+
get source() {
|
|
4616
|
+
return this.#stmt.sourceSQL;
|
|
4617
|
+
}
|
|
4618
|
+
/**
|
|
4619
|
+
* better-sqlite3's `reader` flag: does this statement return rows?
|
|
4620
|
+
*
|
|
4621
|
+
* `node:sqlite` has no equivalent, so it is derived from the prepared statement's own column
|
|
4622
|
+
* count -- SQLite gives a row-producing statement its result columns at prepare time and gives a
|
|
4623
|
+
* non-producing one none. That is a derivation, and this is the third defence-in-depth layer in
|
|
4624
|
+
* `sqlite_query.ts`'s read-only guard, so it is not taken on faith: the driver tests run both
|
|
4625
|
+
* libraries side by side over SELECT, a CTE, VALUES, EXPLAIN, an empty-result SELECT, INSERT,
|
|
4626
|
+
* UPDATE, DELETE, CREATE, a reading PRAGMA and an assigning PRAGMA, and require every verdict to
|
|
4627
|
+
* agree. If a future SQLite statement form ever breaks the equivalence, that test fails rather
|
|
4628
|
+
* than the guard quietly weakening.
|
|
4629
|
+
*/
|
|
4630
|
+
get reader() {
|
|
4631
|
+
return attempt(() => this.#stmt.columns()).length > 0;
|
|
4632
|
+
}
|
|
4633
|
+
// A plucked row is "the first column", which for an object row means the first *inserted* key. V8 preserves insertion order for string keys, and node:sqlite builds the row by walking the result columns left to right, so Object.values()[0] is the leftmost column -- not the column named in the SQL text, the same rule better-sqlite3 applies.
|
|
4634
|
+
#shape(row) {
|
|
4635
|
+
if (!this.#pluck || row === void 0 || row === null) return row;
|
|
4636
|
+
const values = Object.values(row);
|
|
4637
|
+
return values.length === 0 ? void 0 : values[0];
|
|
4638
|
+
}
|
|
4639
|
+
get(...params) {
|
|
4640
|
+
return this.#shape(attempt(() => this.#stmt.get(...params)));
|
|
4641
|
+
}
|
|
4642
|
+
all(...params) {
|
|
4643
|
+
const rows = attempt(() => this.#stmt.all(...params));
|
|
4644
|
+
return this.#pluck ? rows.map((r) => this.#shape(r)) : rows;
|
|
4645
|
+
}
|
|
4646
|
+
run(...params) {
|
|
4647
|
+
return attempt(() => this.#stmt.run(...params));
|
|
4648
|
+
}
|
|
4649
|
+
// Wrapped rather than returned directly so pluck applies lazily, one row at a time: the whole point of iterate() here is that sqlite_query.ts caps the row count without buffering the rest, and mapping the iterator through .all() first would defeat that.
|
|
4650
|
+
*iterate(...params) {
|
|
4651
|
+
const rows = attempt(() => this.#stmt.iterate(...params))[Symbol.iterator]();
|
|
4652
|
+
for (; ; ) {
|
|
4653
|
+
const next = attempt(() => rows.next());
|
|
4654
|
+
if (next.done === true) return;
|
|
4655
|
+
yield this.#shape(next.value);
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
pluck(toggle = true) {
|
|
4659
|
+
this.#pluck = toggle;
|
|
4660
|
+
return this;
|
|
4661
|
+
}
|
|
4662
|
+
safeIntegers(toggle = true) {
|
|
4663
|
+
this.#stmt.setReadBigInts(toggle);
|
|
4664
|
+
return this;
|
|
4665
|
+
}
|
|
4666
|
+
columns() {
|
|
4667
|
+
return attempt(() => this.#stmt.columns());
|
|
4668
|
+
}
|
|
4669
|
+
};
|
|
4670
|
+
var Database = class {
|
|
4671
|
+
#db;
|
|
4672
|
+
#path;
|
|
4673
|
+
#readonly;
|
|
4674
|
+
#savepoints = 0;
|
|
4675
|
+
constructor(dbPath, options = {}) {
|
|
4676
|
+
const wantsExisting = options.readonly === true || options.fileMustExist === true;
|
|
4677
|
+
if (wantsExisting && dbPath !== ":memory:" && !fs6.existsSync(dbPath)) {
|
|
4678
|
+
throw new Error("unable to open database file");
|
|
4679
|
+
}
|
|
4680
|
+
this.#db = attempt(() => new DatabaseSync(dbPath, {
|
|
4681
|
+
readOnly: options.readonly === true,
|
|
4682
|
+
// sqlite-vec is loaded through db.loadExtension by initConnection, which node:sqlite refuses unless the connection opted in at construction. Harmless when no extension is ever loaded.
|
|
4683
|
+
allowExtension: true,
|
|
4684
|
+
// better-sqlite3 opens every connection with busy_timeout at 5000ms; node:sqlite opens at 0, so a connection that named no timeout would silently go from five seconds of patience to none. db.ts overrides this to 15000 in initConnection, but sqlite_query.ts opens a user's arbitrary database readonly and takes whatever the default is -- which would have turned ordinary contention with another writer into an immediate "database is locked".
|
|
4685
|
+
timeout: options.timeout ?? 5e3
|
|
4686
|
+
}));
|
|
4687
|
+
this.#path = dbPath;
|
|
4688
|
+
this.#readonly = options.readonly === true;
|
|
4689
|
+
}
|
|
4690
|
+
get open() {
|
|
4691
|
+
return this.#db.isOpen;
|
|
4692
|
+
}
|
|
4693
|
+
get inTransaction() {
|
|
4694
|
+
return this.#db.isTransaction;
|
|
4695
|
+
}
|
|
4696
|
+
get readonly() {
|
|
4697
|
+
return this.#readonly;
|
|
4698
|
+
}
|
|
4699
|
+
get name() {
|
|
4700
|
+
return this.#path;
|
|
4701
|
+
}
|
|
4702
|
+
prepare(sql) {
|
|
4703
|
+
return new Statement(attempt(() => this.#db.prepare(sql)));
|
|
4704
|
+
}
|
|
4705
|
+
exec(sql) {
|
|
4706
|
+
attempt(() => this.#db.exec(sql));
|
|
4707
|
+
}
|
|
4708
|
+
pragma(source, options = {}) {
|
|
4709
|
+
const rows = attempt(() => this.#db.prepare(`PRAGMA ${source}`).all());
|
|
4710
|
+
if (options.simple !== true) return rows;
|
|
4711
|
+
const first = rows[0];
|
|
4712
|
+
if (first === void 0) return void 0;
|
|
4713
|
+
const values = Object.values(first);
|
|
4714
|
+
return values.length === 0 ? void 0 : values[0];
|
|
4715
|
+
}
|
|
4716
|
+
function(name, options, fn) {
|
|
4717
|
+
attempt(() => this.#db.function(name, options, fn));
|
|
4718
|
+
}
|
|
4719
|
+
loadExtension(extensionPath) {
|
|
4720
|
+
attempt(() => this.#db.loadExtension(extensionPath));
|
|
4721
|
+
}
|
|
4722
|
+
close() {
|
|
4723
|
+
attempt(() => this.#db.close());
|
|
4724
|
+
}
|
|
4725
|
+
/**
|
|
4726
|
+
* Wrap `fn` so it runs inside a transaction, committing on return and rolling back on throw.
|
|
4727
|
+
*
|
|
4728
|
+
* Nesting uses SAVEPOINT, which is what makes it safe for a transactional helper to call another
|
|
4729
|
+
* one: an inner `BEGIN` would throw ("cannot start a transaction within a transaction"), an inner
|
|
4730
|
+
* SAVEPOINT composes. Whether we are nested is read from SQLite via `isTransaction` rather than
|
|
4731
|
+
* tracked in a counter here, so a transaction some other code path opened still nests correctly.
|
|
4732
|
+
*
|
|
4733
|
+
* The rollback is best-effort and never replaces the caller's error: if the ROLLBACK itself fails
|
|
4734
|
+
* -- the connection died, the transaction was already unwound -- the original failure is still
|
|
4735
|
+
* what propagates, because that is the one that explains what went wrong.
|
|
4736
|
+
*/
|
|
4737
|
+
transaction(fn) {
|
|
4738
|
+
const build = (beginSql) => (...args) => {
|
|
4739
|
+
if (this.#db.isTransaction) {
|
|
4740
|
+
const name = `tg_sp_${this.#savepoints++}`;
|
|
4741
|
+
attempt(() => this.#db.exec(`SAVEPOINT ${name}`));
|
|
4742
|
+
try {
|
|
4743
|
+
const result = fn(...args);
|
|
4744
|
+
attempt(() => this.#db.exec(`RELEASE ${name}`));
|
|
4745
|
+
return result;
|
|
4746
|
+
} catch (e) {
|
|
4747
|
+
try {
|
|
4748
|
+
attempt(() => this.#db.exec(`ROLLBACK TO ${name}`));
|
|
4749
|
+
attempt(() => this.#db.exec(`RELEASE ${name}`));
|
|
4750
|
+
} catch {
|
|
4751
|
+
}
|
|
4752
|
+
throw e;
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
attempt(() => this.#db.exec(beginSql));
|
|
4756
|
+
try {
|
|
4757
|
+
const result = fn(...args);
|
|
4758
|
+
attempt(() => this.#db.exec("COMMIT"));
|
|
4759
|
+
return result;
|
|
4760
|
+
} catch (e) {
|
|
4761
|
+
try {
|
|
4762
|
+
attempt(() => this.#db.exec("ROLLBACK"));
|
|
4763
|
+
} catch {
|
|
4764
|
+
}
|
|
4765
|
+
throw e;
|
|
4766
|
+
}
|
|
4767
|
+
};
|
|
4768
|
+
const wrapped = build("BEGIN");
|
|
4769
|
+
wrapped.default = wrapped;
|
|
4770
|
+
wrapped.deferred = build("BEGIN");
|
|
4771
|
+
wrapped.immediate = build("BEGIN IMMEDIATE");
|
|
4772
|
+
wrapped.exclusive = build("BEGIN EXCLUSIVE");
|
|
4773
|
+
return wrapped;
|
|
4774
|
+
}
|
|
4775
|
+
};
|
|
4776
|
+
|
|
4777
|
+
// src/db.ts
|
|
4778
|
+
var _require2 = createRequire3(import.meta.url);
|
|
4446
4779
|
var _connections = /* @__PURE__ */ new Map();
|
|
4447
4780
|
var SCHEMA_SQL = `
|
|
4448
4781
|
CREATE TABLE IF NOT EXISTS files (
|
|
@@ -4642,6 +4975,26 @@ CREATE TABLE IF NOT EXISTS skill_version_snapshots (
|
|
|
4642
4975
|
loaded_commands_json TEXT NOT NULL,
|
|
4643
4976
|
notified_at REAL
|
|
4644
4977
|
);
|
|
4978
|
+
|
|
4979
|
+
-- Which embedding stack produced the vectors currently in chunk_vectors -- the model, its
|
|
4980
|
+
-- pinned revision, and the inference runtime (see embeddingProvenance in embeddings.ts). The
|
|
4981
|
+
-- vector table itself is vec0(rowid, embedding) and has nowhere to record this, so without
|
|
4982
|
+
-- this row a database that was embedded by one stack and then added to by another holds two
|
|
4983
|
+
-- incomparable sets of vectors under one index, with nothing able to tell them apart. That is
|
|
4984
|
+
-- not hypothetical: global.db is machine-wide across every project on the machine (see
|
|
4985
|
+
-- constants.ts), so upgrading the runtime, or changing the model or its pinned revision, mixes
|
|
4986
|
+
-- old and new vectors for as long as the old files go untouched. Measured drift between two
|
|
4987
|
+
-- runtime versions of the same quantized model is 0.9925-0.9978 cosine on the final vector --
|
|
4988
|
+
-- small, but enough to reorder near-ties, and invisible to every existing check.
|
|
4989
|
+
--
|
|
4990
|
+
-- Single-row by construction (the CHECK pins the key), because there is exactly one vector
|
|
4991
|
+
-- table per database. An EMPTY table on a database that already holds chunks means the vectors
|
|
4992
|
+
-- predate this stamp and their provenance is unknowable -- see ensureEmbeddingProvenance, which
|
|
4993
|
+
-- treats that exactly like a mismatch. That is what makes this work without a migration step.
|
|
4994
|
+
CREATE TABLE IF NOT EXISTS embedding_provenance (
|
|
4995
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
4996
|
+
provenance TEXT NOT NULL
|
|
4997
|
+
);
|
|
4645
4998
|
`;
|
|
4646
4999
|
var FTS_SQL = `
|
|
4647
5000
|
CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(
|
|
@@ -4692,7 +5045,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
4692
5045
|
VALUES (new.row_id, new.label, new.content);
|
|
4693
5046
|
END;
|
|
4694
5047
|
`;
|
|
4695
|
-
var SCHEMA_VERSION =
|
|
5048
|
+
var SCHEMA_VERSION = 12;
|
|
4696
5049
|
function alterTableIdempotent(conn, sql) {
|
|
4697
5050
|
try {
|
|
4698
5051
|
conn.exec(sql);
|
|
@@ -4723,7 +5076,7 @@ function purgeDotenvEmbeddings(conn) {
|
|
|
4723
5076
|
var MIGRATIONS = {
|
|
4724
5077
|
// v1 -> v2: adds files.embed_sha, tracked separately from files.sha so embedding freshness can be gated independently of parse freshness (see makeIndexer in worker.ts). A pre-existing v1 database's `files` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, so a genuine ALTER TABLE failure is never silently lost.
|
|
4725
5078
|
1: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN embed_sha TEXT"),
|
|
4726
|
-
// v2 -> v3: adds files.retry_count, a durable per-path counter for consecutive transient-read-failure requeues (see MAX_TRANSIENT_RETRIES / requeueDirtyPath /
|
|
5079
|
+
// v2 -> v3: adds files.retry_count, a durable per-path counter for consecutive transient-read-failure requeues (see MAX_TRANSIENT_RETRIES / requeueDirtyPath / clearRetryCount in worker.ts). Previously this counter lived only in an in-memory Map inside worker.ts, which meant the retry-count reset -- run at the time in the short-lived hook CLI process -- could never actually reach the long-lived detached daemon process's own copy of that Map: they are different Node processes with no shared memory, so the reset was a silent no-op in the real deployed topology. Persisting the counter in `files` makes it visible to both processes via the one thing they do share: the index DB. Same swallow-duplicate-column pattern as v1 -> v2 above.
|
|
4727
5080
|
2: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN retry_count INTEGER NOT NULL DEFAULT 0"),
|
|
4728
5081
|
// v8 -> v9: adds symbols.parent (see SCHEMA_VERSION comment above for why). A pre-existing v8 database's `symbols` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v1 -> v2 / v2 -> v3 above.
|
|
4729
5082
|
8: (conn) => alterTableIdempotent(conn, "ALTER TABLE symbols ADD COLUMN parent TEXT NOT NULL DEFAULT ''"),
|
|
@@ -4743,13 +5096,32 @@ function runMigrations(conn, fromVersion, toVersion) {
|
|
|
4743
5096
|
MIGRATIONS[v]?.(conn);
|
|
4744
5097
|
}
|
|
4745
5098
|
}
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
5099
|
+
var WAL_SWITCH_DEADLINE_MS = 15e3;
|
|
5100
|
+
function enableWalWithRetry(conn, budgetMs = WAL_SWITCH_DEADLINE_MS) {
|
|
5101
|
+
const deadline = Date.now() + budgetMs;
|
|
5102
|
+
let lastError;
|
|
5103
|
+
for (; ; ) {
|
|
5104
|
+
try {
|
|
5105
|
+
const mode = conn.pragma("journal_mode = WAL", { simple: true });
|
|
5106
|
+
if (String(mode).toLowerCase() === "wal") return;
|
|
5107
|
+
lastError = new Error(`got: ${String(mode)}`);
|
|
5108
|
+
} catch (e) {
|
|
5109
|
+
lastError = e;
|
|
5110
|
+
}
|
|
5111
|
+
try {
|
|
5112
|
+
if (String(conn.pragma("journal_mode", { simple: true })).toLowerCase() === "wal") return;
|
|
5113
|
+
} catch {
|
|
5114
|
+
}
|
|
5115
|
+
if (Date.now() >= deadline) {
|
|
5116
|
+
throw new Error(`db: failed to enable WAL mode (${lastError instanceof Error ? lastError.message : String(lastError)})`);
|
|
5117
|
+
}
|
|
5118
|
+
sleepSync(25);
|
|
4750
5119
|
}
|
|
4751
|
-
|
|
5120
|
+
}
|
|
5121
|
+
function initConnection(conn) {
|
|
4752
5122
|
conn.pragma("busy_timeout = 15000");
|
|
5123
|
+
enableWalWithRetry(conn);
|
|
5124
|
+
conn.pragma("synchronous = NORMAL");
|
|
4753
5125
|
conn.function(
|
|
4754
5126
|
"TG_LOWER",
|
|
4755
5127
|
{ deterministic: true },
|
|
@@ -4767,7 +5139,7 @@ function initConnection(conn) {
|
|
|
4767
5139
|
} catch {
|
|
4768
5140
|
}
|
|
4769
5141
|
try {
|
|
4770
|
-
const sqliteVec =
|
|
5142
|
+
const sqliteVec = _require2("sqlite-vec");
|
|
4771
5143
|
sqliteVec.load(conn);
|
|
4772
5144
|
conn.exec(
|
|
4773
5145
|
`CREATE VIRTUAL TABLE IF NOT EXISTS chunk_vectors USING vec0(
|
|
@@ -4798,7 +5170,7 @@ function getDb(dbPath) {
|
|
|
4798
5170
|
try {
|
|
4799
5171
|
ensureDirSync(dir);
|
|
4800
5172
|
} catch (e) {
|
|
4801
|
-
if (e.code !== "EEXIST" || !
|
|
5173
|
+
if (e.code !== "EEXIST" || !fs7.existsSync(dir)) throw e;
|
|
4802
5174
|
}
|
|
4803
5175
|
const conn = new Database(resolved);
|
|
4804
5176
|
try {
|
|
@@ -5493,7 +5865,8 @@ function _renderInsightsSection(stats) {
|
|
|
5493
5865
|
function dim(s) {
|
|
5494
5866
|
return `${fg(...C.TEXT_MUTED)}${s}${RESET}`;
|
|
5495
5867
|
}
|
|
5496
|
-
const
|
|
5868
|
+
const savingKinds = stats.by_kind.filter((k) => k.bytes > 0);
|
|
5869
|
+
const topKind = savingKinds.reduce((max, k) => k.bytes > (max?.bytes || -Infinity) ? k : max, savingKinds[0]);
|
|
5497
5870
|
if (topKind) {
|
|
5498
5871
|
const share = stats.totals.bytes > 0 ? topKind.bytes / stats.totals.bytes : 0;
|
|
5499
5872
|
lines.push(
|
|
@@ -5506,7 +5879,7 @@ function _renderInsightsSection(stats) {
|
|
|
5506
5879
|
`${_M}${bullet} ${dim(_STATS_MESSAGES.insights.mostActive)}${fg(...C.TEXT_PRIMARY)}${topDay.date}${RESET}${dim(" \u2014 ")}${topDay.events.toLocaleString()} events, ${_fmtBytes(topDay.bytes)}${dim(" saved")}`
|
|
5507
5880
|
);
|
|
5508
5881
|
}
|
|
5509
|
-
const tokenKinds = stats.by_kind.filter((k) => !k.bytes_mode_only);
|
|
5882
|
+
const tokenKinds = stats.by_kind.filter((k) => !k.bytes_mode_only && k.tokens > 0);
|
|
5510
5883
|
const topToken = tokenKinds.reduce((max, k) => k.tokens > (max?.tokens || -Infinity) ? k : max, tokenKinds[0]);
|
|
5511
5884
|
if (topToken) {
|
|
5512
5885
|
lines.push(
|
|
@@ -5657,6 +6030,8 @@ var KIND_TO_SOURCE = {
|
|
|
5657
6030
|
// Cold first load of an oversized skill where preSkillHandler inlined the compact slice in its reply instead of pointing at `skill-body --compact`. Unlike its skill_oversized_first_load sibling (event-only, 0 bytes -- the pointer deny saves nothing by itself, the follow-up command does) this one records real savings: the full body never landed, the slice did, so bytesSaved is body minus slice.
|
|
5658
6031
|
skill_compact_inlined: SOURCE_SKILL,
|
|
5659
6032
|
secret_redacted: SOURCE_OTHER,
|
|
6033
|
+
// Measurement of what a compaction produced (hooks_compact.ts postCompactHandler): summary size and how many manifest paths survived into it. SOURCE_OTHER and always recorded at (0, 0) -- the summary was written whether or not token-goat was watching, so there is no counterfactual in which those bytes were saved. Filing it anywhere with a savings total would credit token-goat for the whole summary, which is the accounting mistake this registry exists to prevent.
|
|
6034
|
+
compact_summary: SOURCE_OTHER,
|
|
5660
6035
|
// Envelope compaction of an oversized subagent report (hooks_agent_spawn.ts). SOURCE_CONTENT, not SOURCE_HINT: the handler's sibling session_hint entry is advisory (it only appends a recall pointer and genuinely saves nothing), whereas this kind records a real rewrite with real bytes removed, so filing it under the advisory bucket would understate the compaction and repeat the zero-savings desync this registry keeps getting bitten by.
|
|
5661
6036
|
agent_report_compact: SOURCE_CONTENT,
|
|
5662
6037
|
// Decline counterpart to agent_report_compact: the fence-collapse net-benefit gate ran and found at least one over-long fence, but declined to rewrite because net savings did not clear the notice cost. Always recorded at (0, 0) -- see the recordStat call site -- so it never contributes to any savings total; it exists purely to make gate hit-rate and near-misses visible instead of the decline being invisible.
|
|
@@ -6106,7 +6481,14 @@ var SECRET_PATTERNS = [
|
|
|
6106
6481
|
// realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical
|
|
6107
6482
|
// anchor here -- each of the three dot-separated segments requires a minimum length to avoid
|
|
6108
6483
|
// matching a short, coincidentally dotted token.
|
|
6109
|
-
|
|
6484
|
+
//
|
|
6485
|
+
// The trailing `={0,2}` on each segment is what makes a padded token match. Base64url as the JWT
|
|
6486
|
+
// spec defines it drops the `=` padding, but producers that reach for a plain base64 encoder
|
|
6487
|
+
// emit it anyway, and a `=` in the header or payload segment used to defeat the match outright:
|
|
6488
|
+
// not a partial redaction, but none at all, so the entire token was printed. `=` cannot appear
|
|
6489
|
+
// anywhere except the end of a segment, since it is not one of the characters the segment body
|
|
6490
|
+
// allows, so accepting it here cannot widen the match onto anything else.
|
|
6491
|
+
["jwt", /eyJ[A-Za-z0-9_-]{10,}={0,2}\.[A-Za-z0-9_-]{10,}={0,2}\.[A-Za-z0-9_-]{10,}={0,2}/g],
|
|
6110
6492
|
["npm_token", /npm_[A-Za-z0-9]{36}/g],
|
|
6111
6493
|
// rk_live_ (restricted keys) share the sk_live_/sk_test_ secret-key shape and risk level, so
|
|
6112
6494
|
// one pattern covers all three rather than adding a near-duplicate entry.
|
|
@@ -6251,6 +6633,7 @@ function stripAnsiCodes(text) {
|
|
|
6251
6633
|
export {
|
|
6252
6634
|
VERSION,
|
|
6253
6635
|
dataDir,
|
|
6636
|
+
ensureDataDirPrivate,
|
|
6254
6637
|
globalDbPath,
|
|
6255
6638
|
configPath,
|
|
6256
6639
|
ENV_KEYS,
|
|
@@ -6301,6 +6684,7 @@ export {
|
|
|
6301
6684
|
countNoun,
|
|
6302
6685
|
excludeTestsHiddenNote,
|
|
6303
6686
|
countContentLines,
|
|
6687
|
+
pushAll,
|
|
6304
6688
|
escapeRegExp,
|
|
6305
6689
|
windowsCmdQuoteArg,
|
|
6306
6690
|
redactUrlQuery,
|
|
@@ -6338,12 +6722,14 @@ export {
|
|
|
6338
6722
|
lastProjectConfigLockedKeys,
|
|
6339
6723
|
getProjectConfigInfo,
|
|
6340
6724
|
resolveConfigKeyLayer,
|
|
6725
|
+
readConfigSource,
|
|
6341
6726
|
isAutoTriggerMultiplierExplicit,
|
|
6342
6727
|
loadConfig,
|
|
6343
6728
|
invalidateConfigCache,
|
|
6344
6729
|
loadPersistedConfig,
|
|
6345
6730
|
CONFIG_KEY_ENV_OVERRIDES,
|
|
6346
6731
|
saveConfig,
|
|
6732
|
+
Database,
|
|
6347
6733
|
precedingDocComment,
|
|
6348
6734
|
buildLineIndex,
|
|
6349
6735
|
offsetToLine,
|