squadrant 0.27.0 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +322 -289
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +320 -289
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
package/dist/squadrantd.js
CHANGED
|
@@ -9408,16 +9408,275 @@ var init_paths = __esm({
|
|
|
9408
9408
|
}
|
|
9409
9409
|
});
|
|
9410
9410
|
|
|
9411
|
-
// packages/core/dist/knowledge/
|
|
9411
|
+
// packages/core/dist/knowledge/ingest.js
|
|
9412
|
+
import crypto3 from "crypto";
|
|
9412
9413
|
import fs15 from "fs";
|
|
9413
9414
|
import os7 from "os";
|
|
9414
9415
|
import path16 from "path";
|
|
9416
|
+
import { execFile as execFile2 } from "child_process";
|
|
9417
|
+
import { promisify as promisify2 } from "util";
|
|
9418
|
+
function refFor(kbRoot, file) {
|
|
9419
|
+
const rel = path16.relative(kbRoot, file);
|
|
9420
|
+
if (rel && !rel.startsWith("..") && !path16.isAbsolute(rel))
|
|
9421
|
+
return rel.split(path16.sep).join("/");
|
|
9422
|
+
const home = os7.homedir();
|
|
9423
|
+
return file.startsWith(home + path16.sep) ? `~/${path16.relative(home, file).split(path16.sep).join("/")}` : file;
|
|
9424
|
+
}
|
|
9425
|
+
function readState2(kbRoot, ref) {
|
|
9426
|
+
try {
|
|
9427
|
+
return JSON.parse(fs15.readFileSync(stampFile(kbRoot, ref), "utf8"));
|
|
9428
|
+
} catch {
|
|
9429
|
+
return null;
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
function writeState(kbRoot, st) {
|
|
9433
|
+
fs15.mkdirSync(path16.join(kbRoot, CONVERTED_DIR), { recursive: true });
|
|
9434
|
+
fs15.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
|
|
9435
|
+
}
|
|
9436
|
+
function globToRegExp(glob) {
|
|
9437
|
+
let re = "";
|
|
9438
|
+
for (let i = 0; i < glob.length; i++) {
|
|
9439
|
+
const c = glob[i];
|
|
9440
|
+
if (c === "*") {
|
|
9441
|
+
if (glob[i + 1] === "*") {
|
|
9442
|
+
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
9443
|
+
i += glob[i + 2] === "/" ? 2 : 1;
|
|
9444
|
+
} else
|
|
9445
|
+
re += "[^/]*";
|
|
9446
|
+
} else if (c === "?")
|
|
9447
|
+
re += "[^/]";
|
|
9448
|
+
else
|
|
9449
|
+
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
9450
|
+
}
|
|
9451
|
+
return new RegExp(`^${re}$`);
|
|
9452
|
+
}
|
|
9453
|
+
function walkFiles(dir, out = []) {
|
|
9454
|
+
if (!fs15.existsSync(dir))
|
|
9455
|
+
return out;
|
|
9456
|
+
for (const ent of fs15.readdirSync(dir, { withFileTypes: true })) {
|
|
9457
|
+
if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
|
|
9458
|
+
continue;
|
|
9459
|
+
const full = path16.join(dir, ent.name);
|
|
9460
|
+
if (ent.isDirectory())
|
|
9461
|
+
walkFiles(full, out);
|
|
9462
|
+
else if (ent.isFile())
|
|
9463
|
+
out.push(full);
|
|
9464
|
+
}
|
|
9465
|
+
return out;
|
|
9466
|
+
}
|
|
9467
|
+
function expandSource(kbRoot, entry) {
|
|
9468
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
9469
|
+
if (!/[*?]/.test(entry.path))
|
|
9470
|
+
return fs15.existsSync(abs) && fs15.statSync(abs).isFile() ? [abs] : [];
|
|
9471
|
+
const base = abs.split(/[*?]/)[0];
|
|
9472
|
+
const root = base.endsWith(path16.sep) ? base : path16.dirname(base);
|
|
9473
|
+
const re = globToRegExp(abs.split(path16.sep).join("/"));
|
|
9474
|
+
return walkFiles(root).filter((f) => re.test(f.split(path16.sep).join("/"))).sort();
|
|
9475
|
+
}
|
|
9476
|
+
function detectChange(kbRoot, file) {
|
|
9477
|
+
const ref = refFor(kbRoot, file);
|
|
9478
|
+
const st = fs15.statSync(file);
|
|
9479
|
+
const prior = readState2(kbRoot, ref);
|
|
9480
|
+
if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
|
|
9481
|
+
return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
9482
|
+
}
|
|
9483
|
+
const sha = sha256(file);
|
|
9484
|
+
return { ref, changed: !prior || prior.sha !== sha, stamp: { sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
9485
|
+
}
|
|
9486
|
+
function splitSections(text) {
|
|
9487
|
+
const cuts = [];
|
|
9488
|
+
const re = /^#{1,6}[ \t]+(.+)$/gm;
|
|
9489
|
+
for (let m = re.exec(text); m; m = re.exec(text))
|
|
9490
|
+
cuts.push({ at: m.index, heading: m[1].trim() });
|
|
9491
|
+
if (!cuts.length || cuts[0].at > 0)
|
|
9492
|
+
cuts.unshift({ at: 0 });
|
|
9493
|
+
const spans = [];
|
|
9494
|
+
cuts.forEach((c, i) => {
|
|
9495
|
+
const end = i + 1 < cuts.length ? cuts[i + 1].at : text.length;
|
|
9496
|
+
let start = c.at;
|
|
9497
|
+
while (end - start > SECTION_TARGET_CHARS * 1.5) {
|
|
9498
|
+
const brk = text.indexOf("\n\n", start + SECTION_TARGET_CHARS);
|
|
9499
|
+
if (brk < 0 || brk >= end)
|
|
9500
|
+
break;
|
|
9501
|
+
spans.push({ index: 0, start, end: brk, heading: c.heading });
|
|
9502
|
+
start = brk + 2;
|
|
9503
|
+
}
|
|
9504
|
+
if (text.slice(start, end).trim())
|
|
9505
|
+
spans.push({ index: 0, start, end, heading: c.heading });
|
|
9506
|
+
});
|
|
9507
|
+
return spans.map((s, i) => ({ ...s, index: i }));
|
|
9508
|
+
}
|
|
9509
|
+
async function planIngest(kbRoot, opts) {
|
|
9510
|
+
const converter = opts.converter ?? markitdownConverter;
|
|
9511
|
+
const cap = opts.maxSectionsPerPass ?? DEFAULT_MAX_SECTIONS_PER_PASS;
|
|
9512
|
+
const plan = { sources: [], skipped: [], failed: [], carriedSections: 0, sectionCount: 0, estimatedTokens: 0, existing: opts.existing ?? [] };
|
|
9513
|
+
let budget = cap;
|
|
9514
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9515
|
+
for (const entry of opts.sources) {
|
|
9516
|
+
for (const file of expandSource(kbRoot, entry)) {
|
|
9517
|
+
const { ref, changed, stamp, prior } = detectChange(kbRoot, file);
|
|
9518
|
+
if (seen.has(ref))
|
|
9519
|
+
continue;
|
|
9520
|
+
seen.add(ref);
|
|
9521
|
+
const pending = !!prior && prior.cursor < prior.sections;
|
|
9522
|
+
if (!changed && !pending)
|
|
9523
|
+
continue;
|
|
9524
|
+
if (entry.sensitivity === "local-only" && !opts.localModel) {
|
|
9525
|
+
plan.skipped.push({ ref, reason: "sensitivity: local-only and no local model available" });
|
|
9526
|
+
continue;
|
|
9527
|
+
}
|
|
9528
|
+
if (budget <= 0) {
|
|
9529
|
+
plan.carriedSections += changed ? 1 : prior.sections - prior.cursor;
|
|
9530
|
+
continue;
|
|
9531
|
+
}
|
|
9532
|
+
let text;
|
|
9533
|
+
const conv = convertedFile(kbRoot, ref);
|
|
9534
|
+
try {
|
|
9535
|
+
if (!changed && fs15.existsSync(conv))
|
|
9536
|
+
text = fs15.readFileSync(conv, "utf8");
|
|
9537
|
+
else {
|
|
9538
|
+
text = PASS_THROUGH.has(path16.extname(file).toLowerCase()) ? fs15.readFileSync(file, "utf8") : await converter(file);
|
|
9539
|
+
if (!opts.dryRun) {
|
|
9540
|
+
fs15.mkdirSync(path16.dirname(conv), { recursive: true });
|
|
9541
|
+
fs15.writeFileSync(conv, text);
|
|
9542
|
+
}
|
|
9543
|
+
}
|
|
9544
|
+
} catch (e) {
|
|
9545
|
+
plan.failed.push({ ref, error: e.message.split("\n")[0] });
|
|
9546
|
+
continue;
|
|
9547
|
+
}
|
|
9548
|
+
const all = splitSections(text);
|
|
9549
|
+
const from = changed ? 0 : prior.cursor;
|
|
9550
|
+
const take = all.slice(from, from + budget);
|
|
9551
|
+
budget -= take.length;
|
|
9552
|
+
plan.carriedSections += all.length - from - take.length;
|
|
9553
|
+
plan.sectionCount += take.length;
|
|
9554
|
+
plan.estimatedTokens += Math.ceil(take.reduce((n, s) => n + (s.end - s.start), 0) / CHARS_PER_TOKEN);
|
|
9555
|
+
plan.sources.push({
|
|
9556
|
+
ref,
|
|
9557
|
+
file,
|
|
9558
|
+
converted: conv,
|
|
9559
|
+
sha: stamp.sha,
|
|
9560
|
+
priority: entry.priority,
|
|
9561
|
+
domain: entry.domain,
|
|
9562
|
+
sensitivity: entry.sensitivity,
|
|
9563
|
+
sections: take,
|
|
9564
|
+
totalSections: all.length
|
|
9565
|
+
});
|
|
9566
|
+
if (!opts.dryRun)
|
|
9567
|
+
writeState(kbRoot, { ref, ...stamp, sections: all.length, cursor: from + take.length, priority: entry.priority });
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
return plan;
|
|
9571
|
+
}
|
|
9572
|
+
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome, fileForRef, cacheKey, convertedFile, stampFile, sha256;
|
|
9573
|
+
var init_ingest = __esm({
|
|
9574
|
+
"packages/core/dist/knowledge/ingest.js"() {
|
|
9575
|
+
execFileAsync = promisify2(execFile2);
|
|
9576
|
+
CONVERTED_DIR = ".converted";
|
|
9577
|
+
DEFAULT_MAX_SECTIONS_PER_PASS = 40;
|
|
9578
|
+
CHARS_PER_TOKEN = 4;
|
|
9579
|
+
PASS_THROUGH = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
9580
|
+
SECTION_TARGET_CHARS = 4e3;
|
|
9581
|
+
markitdownConverter = async (file) => {
|
|
9582
|
+
const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
|
|
9583
|
+
return stdout;
|
|
9584
|
+
};
|
|
9585
|
+
expandHome = (p) => p === "~" || p.startsWith("~/") ? path16.join(os7.homedir(), p.slice(1)) : p;
|
|
9586
|
+
fileForRef = (kbRoot, ref) => path16.resolve(kbRoot, expandHome(ref));
|
|
9587
|
+
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
9588
|
+
convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
9589
|
+
stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
9590
|
+
sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
|
|
9591
|
+
}
|
|
9592
|
+
});
|
|
9593
|
+
|
|
9594
|
+
// packages/core/dist/knowledge/verify.js
|
|
9595
|
+
function normalizeWithMap(src, keepBreakHyphen = false) {
|
|
9596
|
+
const out = [];
|
|
9597
|
+
const map2 = [];
|
|
9598
|
+
const push = (s, at) => {
|
|
9599
|
+
for (const ch of s) {
|
|
9600
|
+
out.push(ch);
|
|
9601
|
+
map2.push(at);
|
|
9602
|
+
}
|
|
9603
|
+
};
|
|
9604
|
+
let i = 0;
|
|
9605
|
+
while (i < src.length) {
|
|
9606
|
+
const ch = src[i];
|
|
9607
|
+
if (ch === "-" && /^-[ \t]*\r?\n[ \t]*[a-z]/.test(src.slice(i, i + 40)) && i > 0 && /[A-Za-z]/.test(src[i - 1])) {
|
|
9608
|
+
if (keepBreakHyphen)
|
|
9609
|
+
push("-", i);
|
|
9610
|
+
i++;
|
|
9611
|
+
while (/\s/.test(src[i]))
|
|
9612
|
+
i++;
|
|
9613
|
+
continue;
|
|
9614
|
+
}
|
|
9615
|
+
if (/\s/.test(ch)) {
|
|
9616
|
+
const start = i;
|
|
9617
|
+
while (i < src.length && /\s/.test(src[i]))
|
|
9618
|
+
i++;
|
|
9619
|
+
if (out.length && out[out.length - 1] !== " ")
|
|
9620
|
+
push(" ", start);
|
|
9621
|
+
continue;
|
|
9622
|
+
}
|
|
9623
|
+
if (MARKUP.has(ch)) {
|
|
9624
|
+
i++;
|
|
9625
|
+
continue;
|
|
9626
|
+
}
|
|
9627
|
+
if (LIGATURES[ch])
|
|
9628
|
+
push(LIGATURES[ch], i);
|
|
9629
|
+
else if (QUOTES[ch])
|
|
9630
|
+
push(QUOTES[ch], i);
|
|
9631
|
+
else if (DASHES.has(ch))
|
|
9632
|
+
push("-", i);
|
|
9633
|
+
else
|
|
9634
|
+
push(ch, i);
|
|
9635
|
+
i++;
|
|
9636
|
+
}
|
|
9637
|
+
while (out.length && out[out.length - 1] === " ") {
|
|
9638
|
+
out.pop();
|
|
9639
|
+
map2.pop();
|
|
9640
|
+
}
|
|
9641
|
+
return { text: out.join(""), map: map2 };
|
|
9642
|
+
}
|
|
9643
|
+
function findQuote(source, quote) {
|
|
9644
|
+
const needle = normalizeText(quote);
|
|
9645
|
+
if (!needle)
|
|
9646
|
+
return null;
|
|
9647
|
+
const views = typeof source === "string" ? normalizedViews(source) : source;
|
|
9648
|
+
for (const hay of views) {
|
|
9649
|
+
const at = hay.text.indexOf(needle);
|
|
9650
|
+
if (at >= 0)
|
|
9651
|
+
return [hay.map[at], hay.map[at + needle.length - 1] + 1];
|
|
9652
|
+
}
|
|
9653
|
+
return null;
|
|
9654
|
+
}
|
|
9655
|
+
var LIGATURES, QUOTES, DASHES, MARKUP, normalizeText, normalizedViews, DOCLING_DROP_THRESHOLD, needsDocling, spansOverlap;
|
|
9656
|
+
var init_verify = __esm({
|
|
9657
|
+
"packages/core/dist/knowledge/verify.js"() {
|
|
9658
|
+
LIGATURES = { "\uFB01": "fi", "\uFB02": "fl", "\uFB00": "ff", "\uFB03": "ffi", "\uFB04": "ffl", "\uFB05": "st", "\uFB06": "st" };
|
|
9659
|
+
QUOTES = { "\u2018": "'", "\u2019": "'", "\u201A": "'", "\u201B": "'", "\u201C": '"', "\u201D": '"', "\u201E": '"', "\u201F": '"' };
|
|
9660
|
+
DASHES = /* @__PURE__ */ new Set(["\u2010", "\u2011", "\u2012", "\u2013", "\u2014", "\u2015", "\u2212"]);
|
|
9661
|
+
MARKUP = /* @__PURE__ */ new Set(["*", "_", "`", "\\"]);
|
|
9662
|
+
normalizeText = (s) => normalizeWithMap(s).text;
|
|
9663
|
+
normalizedViews = (src) => [normalizeWithMap(src), normalizeWithMap(src, true)];
|
|
9664
|
+
DOCLING_DROP_THRESHOLD = 0.2;
|
|
9665
|
+
needsDocling = (dropped, total) => total > 0 && dropped / total > DOCLING_DROP_THRESHOLD;
|
|
9666
|
+
spansOverlap = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
9667
|
+
}
|
|
9668
|
+
});
|
|
9669
|
+
|
|
9670
|
+
// packages/core/dist/knowledge/store.js
|
|
9671
|
+
import fs16 from "fs";
|
|
9672
|
+
import os8 from "os";
|
|
9673
|
+
import path17 from "path";
|
|
9415
9674
|
import matter2 from "gray-matter";
|
|
9416
9675
|
function duplicateIdProblem(id, ignored, used) {
|
|
9417
9676
|
return `duplicate id ${id}: ${ignored} is ignored, ${used} is used (live files win over _proposed, then path order). Fix: rename the id in one file, or delete or move one of them.`;
|
|
9418
9677
|
}
|
|
9419
9678
|
function isPendingProposalDup(e, rulesDir) {
|
|
9420
|
-
return e.problems.every((p) => p.startsWith("duplicate id")) &&
|
|
9679
|
+
return e.problems.every((p) => p.startsWith("duplicate id")) && path17.relative(rulesDir, e.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
9421
9680
|
}
|
|
9422
9681
|
function splitStatement(body) {
|
|
9423
9682
|
const first = body.trim().split(/\n\s*\n/)[0] ?? "";
|
|
@@ -9426,8 +9685,8 @@ function splitStatement(body) {
|
|
|
9426
9685
|
function listMarkdown(dir, includeProposed) {
|
|
9427
9686
|
const out = [];
|
|
9428
9687
|
const walk = (d) => {
|
|
9429
|
-
for (const ent of
|
|
9430
|
-
const full =
|
|
9688
|
+
for (const ent of fs16.readdirSync(d, { withFileTypes: true })) {
|
|
9689
|
+
const full = path17.join(d, ent.name);
|
|
9431
9690
|
if (ent.isDirectory()) {
|
|
9432
9691
|
if (ent.name === PROPOSED_DIR && !includeProposed)
|
|
9433
9692
|
continue;
|
|
@@ -9438,11 +9697,11 @@ function listMarkdown(dir, includeProposed) {
|
|
|
9438
9697
|
}
|
|
9439
9698
|
};
|
|
9440
9699
|
walk(dir);
|
|
9441
|
-
const isProposed = (f) =>
|
|
9700
|
+
const isProposed = (f) => path17.relative(dir, f).split(path17.sep).includes(PROPOSED_DIR);
|
|
9442
9701
|
return out.sort((a, b) => Number(isProposed(a)) - Number(isProposed(b)) || (a < b ? -1 : a > b ? 1 : 0));
|
|
9443
9702
|
}
|
|
9444
9703
|
function loadRulesDir(dir, layer, opts = {}) {
|
|
9445
|
-
if (!
|
|
9704
|
+
if (!fs16.existsSync(dir))
|
|
9446
9705
|
return { rules: [], errors: [] };
|
|
9447
9706
|
const rules = [];
|
|
9448
9707
|
const errors = [];
|
|
@@ -9450,7 +9709,7 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
9450
9709
|
for (const file of listMarkdown(dir, opts.includeProposed ?? false)) {
|
|
9451
9710
|
let parsed;
|
|
9452
9711
|
try {
|
|
9453
|
-
parsed = matter2(
|
|
9712
|
+
parsed = matter2(fs16.readFileSync(file, "utf8"), NO_JS_FRONTMATTER);
|
|
9454
9713
|
} catch (e) {
|
|
9455
9714
|
errors.push({ file, problems: [`frontmatter parse error: ${e.message}`] });
|
|
9456
9715
|
continue;
|
|
@@ -9474,14 +9733,14 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
9474
9733
|
function resolveSourceRef(ref, kbRoot, sources) {
|
|
9475
9734
|
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
9476
9735
|
for (const s of sources) {
|
|
9477
|
-
let d =
|
|
9478
|
-
for (let i = 0; i < 6 && d !==
|
|
9479
|
-
d =
|
|
9736
|
+
let d = path17.resolve(kbRoot, expandHome2(s.path.split(/[*?[{]/)[0]));
|
|
9737
|
+
for (let i = 0; i < 6 && d !== path17.dirname(d); i++) {
|
|
9738
|
+
d = path17.dirname(d);
|
|
9480
9739
|
bases.add(d);
|
|
9481
9740
|
}
|
|
9482
9741
|
}
|
|
9483
|
-
const cands = [
|
|
9484
|
-
return cands.find((c) =>
|
|
9742
|
+
const cands = [path17.resolve(kbRoot, expandHome2(ref)), ...[...bases].map((b) => path17.join(b, ref))];
|
|
9743
|
+
return cands.find((c) => fs16.existsSync(c) && fs16.statSync(c).isFile());
|
|
9485
9744
|
}
|
|
9486
9745
|
function validateKb(opts) {
|
|
9487
9746
|
const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
|
|
@@ -9489,7 +9748,7 @@ function validateKb(opts) {
|
|
|
9489
9748
|
const dups = errors.filter((e) => e.problems.some((p) => p.startsWith("duplicate id")) && !isPendingProposalDup(e, opts.rulesDir));
|
|
9490
9749
|
const pendingDups = errors.filter((e) => isPendingProposalDup(e, opts.rulesDir)).length;
|
|
9491
9750
|
const invalid = errors.filter((e) => !dups.includes(e) && !isPendingProposalDup(e, opts.rulesDir));
|
|
9492
|
-
const proposed = rules.filter((r) =>
|
|
9751
|
+
const proposed = rules.filter((r) => path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR)).length;
|
|
9493
9752
|
checks.push({ level: "ok", message: `${rules.length + errors.length} rule files read (${rules.length - proposed} live, ${proposed + pendingDups} proposed parsed OK)` });
|
|
9494
9753
|
if (invalid.length)
|
|
9495
9754
|
for (const e of invalid)
|
|
@@ -9502,7 +9761,7 @@ function validateKb(opts) {
|
|
|
9502
9761
|
else
|
|
9503
9762
|
checks.push({ level: "ok", message: "no duplicate ids" });
|
|
9504
9763
|
const cache = /* @__PURE__ */ new Map();
|
|
9505
|
-
let verified = 0, unresolved = 0;
|
|
9764
|
+
let verified = 0, unresolved = 0, notIngested = 0;
|
|
9506
9765
|
for (const r of rules) {
|
|
9507
9766
|
r.sources.forEach((src, i) => {
|
|
9508
9767
|
const file = resolveSourceRef(src.ref, opts.kbRoot, opts.sources);
|
|
@@ -9510,16 +9769,28 @@ function validateKb(opts) {
|
|
|
9510
9769
|
unresolved++;
|
|
9511
9770
|
return;
|
|
9512
9771
|
}
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9772
|
+
const key = `${src.ref}\0${file}`;
|
|
9773
|
+
if (!cache.has(key)) {
|
|
9774
|
+
const conv = readState2(opts.kbRoot, src.ref) ? convertedFile(opts.kbRoot, src.ref) : null;
|
|
9775
|
+
const cached = !!conv && fs16.existsSync(conv);
|
|
9776
|
+
cache.set(key, {
|
|
9777
|
+
hay: normalizedViews(fs16.readFileSync(cached ? conv : file, "utf8")),
|
|
9778
|
+
convertible: !cached && !PASS_THROUGH.has(path17.extname(file).toLowerCase())
|
|
9779
|
+
});
|
|
9780
|
+
}
|
|
9781
|
+
const { hay, convertible } = cache.get(key);
|
|
9782
|
+
if (findQuote(hay, src.quote))
|
|
9516
9783
|
verified++;
|
|
9784
|
+
else if (convertible)
|
|
9785
|
+
notIngested++;
|
|
9517
9786
|
else
|
|
9518
9787
|
checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
|
|
9519
9788
|
});
|
|
9520
9789
|
}
|
|
9521
9790
|
if (!checks.some((c) => c.message.startsWith("quote not found")))
|
|
9522
9791
|
checks.push({ level: "ok", message: `${verified} source quotes found in their source files` });
|
|
9792
|
+
if (notIngested)
|
|
9793
|
+
checks.push({ level: "skip", message: `${notIngested} source refs need conversion but have no .converted cache, quote not checked (run \`squadrant knowledge ingest <kb>\`)` });
|
|
9523
9794
|
if (unresolved)
|
|
9524
9795
|
checks.push({ level: "skip", message: `${unresolved} source refs not resolvable on this machine, quote not checked` });
|
|
9525
9796
|
if (opts.domains) {
|
|
@@ -9530,22 +9801,24 @@ function validateKb(opts) {
|
|
|
9530
9801
|
}
|
|
9531
9802
|
return { checks, ok: !checks.some((c) => c.level === "fail") };
|
|
9532
9803
|
}
|
|
9533
|
-
var NO_JS_FRONTMATTER,
|
|
9804
|
+
var NO_JS_FRONTMATTER, expandHome2;
|
|
9534
9805
|
var init_store2 = __esm({
|
|
9535
9806
|
"packages/core/dist/knowledge/store.js"() {
|
|
9536
9807
|
init_dist();
|
|
9808
|
+
init_ingest();
|
|
9537
9809
|
init_paths();
|
|
9810
|
+
init_verify();
|
|
9538
9811
|
NO_JS_FRONTMATTER = {
|
|
9539
9812
|
engines: { javascript: { parse: () => {
|
|
9540
9813
|
throw new Error("only YAML front matter is allowed");
|
|
9541
9814
|
} } }
|
|
9542
9815
|
};
|
|
9543
|
-
|
|
9816
|
+
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path17.join(os8.homedir(), p.slice(1)) : p;
|
|
9544
9817
|
}
|
|
9545
9818
|
});
|
|
9546
9819
|
|
|
9547
9820
|
// packages/core/dist/knowledge/layers.js
|
|
9548
|
-
import
|
|
9821
|
+
import fs17 from "fs";
|
|
9549
9822
|
function loadKbRules(cfg, kb, opts = {}) {
|
|
9550
9823
|
return loadRulesDir(kbRulesDir(cfg, kb), `kb:${kb}`, opts);
|
|
9551
9824
|
}
|
|
@@ -9557,7 +9830,7 @@ function resolveProjectRules(cfg, project, opts = {}) {
|
|
|
9557
9830
|
const errors = [];
|
|
9558
9831
|
const warnings = [];
|
|
9559
9832
|
for (const kb of subscribedKbs(cfg, project)) {
|
|
9560
|
-
if (!
|
|
9833
|
+
if (!fs17.existsSync(kbDir(cfg, kb))) {
|
|
9561
9834
|
warnings.push(`knowledge base '${kb}' not found (run: squadrant knowledge init ${kb})`);
|
|
9562
9835
|
continue;
|
|
9563
9836
|
}
|
|
@@ -9595,8 +9868,8 @@ var init_layers = __esm({
|
|
|
9595
9868
|
});
|
|
9596
9869
|
|
|
9597
9870
|
// packages/core/dist/knowledge/index-file.js
|
|
9598
|
-
import
|
|
9599
|
-
import
|
|
9871
|
+
import fs18 from "fs";
|
|
9872
|
+
import path18 from "path";
|
|
9600
9873
|
function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
|
|
9601
9874
|
return {
|
|
9602
9875
|
kb,
|
|
@@ -9605,18 +9878,18 @@ function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
|
|
|
9605
9878
|
};
|
|
9606
9879
|
}
|
|
9607
9880
|
function writeIndex(kbRoot, index) {
|
|
9608
|
-
const file =
|
|
9881
|
+
const file = path18.join(kbRoot, "index.json");
|
|
9609
9882
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
9610
|
-
|
|
9611
|
-
|
|
9883
|
+
fs18.writeFileSync(tmp, JSON.stringify(index, null, 2) + "\n");
|
|
9884
|
+
fs18.renameSync(tmp, file);
|
|
9612
9885
|
return file;
|
|
9613
9886
|
}
|
|
9614
9887
|
function readIndex(kbRoot, kb) {
|
|
9615
|
-
const file =
|
|
9616
|
-
if (!
|
|
9888
|
+
const file = path18.join(kbRoot, "index.json");
|
|
9889
|
+
if (!fs18.existsSync(file))
|
|
9617
9890
|
return { index: null, problem: `index.json missing for kb '${kb}'` };
|
|
9618
9891
|
try {
|
|
9619
|
-
const index = JSON.parse(
|
|
9892
|
+
const index = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
9620
9893
|
if (!Array.isArray(index.rules))
|
|
9621
9894
|
return { index: null, problem: `index.json corrupt for kb '${kb}' (no rules array)` };
|
|
9622
9895
|
return { index };
|
|
@@ -12711,15 +12984,15 @@ var init_js_yaml = __esm({
|
|
|
12711
12984
|
});
|
|
12712
12985
|
|
|
12713
12986
|
// packages/core/dist/knowledge/sources.js
|
|
12714
|
-
import
|
|
12715
|
-
import
|
|
12987
|
+
import fs19 from "fs";
|
|
12988
|
+
import path19 from "path";
|
|
12716
12989
|
function loadSources(kbRoot) {
|
|
12717
|
-
const file =
|
|
12718
|
-
if (!
|
|
12990
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
12991
|
+
if (!fs19.existsSync(file))
|
|
12719
12992
|
return { sources: [], errors: [] };
|
|
12720
12993
|
let data;
|
|
12721
12994
|
try {
|
|
12722
|
-
data = yaml.load(
|
|
12995
|
+
data = yaml.load(fs19.readFileSync(file, "utf8"));
|
|
12723
12996
|
} catch (e) {
|
|
12724
12997
|
return { sources: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
12725
12998
|
}
|
|
@@ -12757,189 +13030,6 @@ var init_sources = __esm({
|
|
|
12757
13030
|
}
|
|
12758
13031
|
});
|
|
12759
13032
|
|
|
12760
|
-
// packages/core/dist/knowledge/ingest.js
|
|
12761
|
-
import crypto3 from "crypto";
|
|
12762
|
-
import fs19 from "fs";
|
|
12763
|
-
import os8 from "os";
|
|
12764
|
-
import path19 from "path";
|
|
12765
|
-
import { execFile as execFile2 } from "child_process";
|
|
12766
|
-
import { promisify as promisify2 } from "util";
|
|
12767
|
-
function refFor(kbRoot, file) {
|
|
12768
|
-
const rel = path19.relative(kbRoot, file);
|
|
12769
|
-
if (rel && !rel.startsWith("..") && !path19.isAbsolute(rel))
|
|
12770
|
-
return rel.split(path19.sep).join("/");
|
|
12771
|
-
const home = os8.homedir();
|
|
12772
|
-
return file.startsWith(home + path19.sep) ? `~/${path19.relative(home, file).split(path19.sep).join("/")}` : file;
|
|
12773
|
-
}
|
|
12774
|
-
function readState2(kbRoot, ref) {
|
|
12775
|
-
try {
|
|
12776
|
-
return JSON.parse(fs19.readFileSync(stampFile(kbRoot, ref), "utf8"));
|
|
12777
|
-
} catch {
|
|
12778
|
-
return null;
|
|
12779
|
-
}
|
|
12780
|
-
}
|
|
12781
|
-
function writeState(kbRoot, st) {
|
|
12782
|
-
fs19.mkdirSync(path19.join(kbRoot, CONVERTED_DIR), { recursive: true });
|
|
12783
|
-
fs19.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
|
|
12784
|
-
}
|
|
12785
|
-
function globToRegExp(glob) {
|
|
12786
|
-
let re = "";
|
|
12787
|
-
for (let i = 0; i < glob.length; i++) {
|
|
12788
|
-
const c = glob[i];
|
|
12789
|
-
if (c === "*") {
|
|
12790
|
-
if (glob[i + 1] === "*") {
|
|
12791
|
-
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
12792
|
-
i += glob[i + 2] === "/" ? 2 : 1;
|
|
12793
|
-
} else
|
|
12794
|
-
re += "[^/]*";
|
|
12795
|
-
} else if (c === "?")
|
|
12796
|
-
re += "[^/]";
|
|
12797
|
-
else
|
|
12798
|
-
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
12799
|
-
}
|
|
12800
|
-
return new RegExp(`^${re}$`);
|
|
12801
|
-
}
|
|
12802
|
-
function walkFiles(dir, out = []) {
|
|
12803
|
-
if (!fs19.existsSync(dir))
|
|
12804
|
-
return out;
|
|
12805
|
-
for (const ent of fs19.readdirSync(dir, { withFileTypes: true })) {
|
|
12806
|
-
if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
|
|
12807
|
-
continue;
|
|
12808
|
-
const full = path19.join(dir, ent.name);
|
|
12809
|
-
if (ent.isDirectory())
|
|
12810
|
-
walkFiles(full, out);
|
|
12811
|
-
else if (ent.isFile())
|
|
12812
|
-
out.push(full);
|
|
12813
|
-
}
|
|
12814
|
-
return out;
|
|
12815
|
-
}
|
|
12816
|
-
function expandSource(kbRoot, entry) {
|
|
12817
|
-
const abs = path19.resolve(kbRoot, expandHome2(entry.path));
|
|
12818
|
-
if (!/[*?]/.test(entry.path))
|
|
12819
|
-
return fs19.existsSync(abs) && fs19.statSync(abs).isFile() ? [abs] : [];
|
|
12820
|
-
const base = abs.split(/[*?]/)[0];
|
|
12821
|
-
const root = base.endsWith(path19.sep) ? base : path19.dirname(base);
|
|
12822
|
-
const re = globToRegExp(abs.split(path19.sep).join("/"));
|
|
12823
|
-
return walkFiles(root).filter((f) => re.test(f.split(path19.sep).join("/"))).sort();
|
|
12824
|
-
}
|
|
12825
|
-
function detectChange(kbRoot, file) {
|
|
12826
|
-
const ref = refFor(kbRoot, file);
|
|
12827
|
-
const st = fs19.statSync(file);
|
|
12828
|
-
const prior = readState2(kbRoot, ref);
|
|
12829
|
-
if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
|
|
12830
|
-
return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
12831
|
-
}
|
|
12832
|
-
const sha = sha256(file);
|
|
12833
|
-
return { ref, changed: !prior || prior.sha !== sha, stamp: { sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
12834
|
-
}
|
|
12835
|
-
function splitSections(text) {
|
|
12836
|
-
const cuts = [];
|
|
12837
|
-
const re = /^#{1,6}[ \t]+(.+)$/gm;
|
|
12838
|
-
for (let m = re.exec(text); m; m = re.exec(text))
|
|
12839
|
-
cuts.push({ at: m.index, heading: m[1].trim() });
|
|
12840
|
-
if (!cuts.length || cuts[0].at > 0)
|
|
12841
|
-
cuts.unshift({ at: 0 });
|
|
12842
|
-
const spans = [];
|
|
12843
|
-
cuts.forEach((c, i) => {
|
|
12844
|
-
const end = i + 1 < cuts.length ? cuts[i + 1].at : text.length;
|
|
12845
|
-
let start = c.at;
|
|
12846
|
-
while (end - start > SECTION_TARGET_CHARS * 1.5) {
|
|
12847
|
-
const brk = text.indexOf("\n\n", start + SECTION_TARGET_CHARS);
|
|
12848
|
-
if (brk < 0 || brk >= end)
|
|
12849
|
-
break;
|
|
12850
|
-
spans.push({ index: 0, start, end: brk, heading: c.heading });
|
|
12851
|
-
start = brk + 2;
|
|
12852
|
-
}
|
|
12853
|
-
if (text.slice(start, end).trim())
|
|
12854
|
-
spans.push({ index: 0, start, end, heading: c.heading });
|
|
12855
|
-
});
|
|
12856
|
-
return spans.map((s, i) => ({ ...s, index: i }));
|
|
12857
|
-
}
|
|
12858
|
-
async function planIngest(kbRoot, opts) {
|
|
12859
|
-
const converter = opts.converter ?? markitdownConverter;
|
|
12860
|
-
const cap = opts.maxSectionsPerPass ?? DEFAULT_MAX_SECTIONS_PER_PASS;
|
|
12861
|
-
const plan = { sources: [], skipped: [], failed: [], carriedSections: 0, sectionCount: 0, estimatedTokens: 0, existing: opts.existing ?? [] };
|
|
12862
|
-
let budget = cap;
|
|
12863
|
-
const seen = /* @__PURE__ */ new Set();
|
|
12864
|
-
for (const entry of opts.sources) {
|
|
12865
|
-
for (const file of expandSource(kbRoot, entry)) {
|
|
12866
|
-
const { ref, changed, stamp, prior } = detectChange(kbRoot, file);
|
|
12867
|
-
if (seen.has(ref))
|
|
12868
|
-
continue;
|
|
12869
|
-
seen.add(ref);
|
|
12870
|
-
const pending = !!prior && prior.cursor < prior.sections;
|
|
12871
|
-
if (!changed && !pending)
|
|
12872
|
-
continue;
|
|
12873
|
-
if (entry.sensitivity === "local-only" && !opts.localModel) {
|
|
12874
|
-
plan.skipped.push({ ref, reason: "sensitivity: local-only and no local model available" });
|
|
12875
|
-
continue;
|
|
12876
|
-
}
|
|
12877
|
-
if (budget <= 0) {
|
|
12878
|
-
plan.carriedSections += changed ? 1 : prior.sections - prior.cursor;
|
|
12879
|
-
continue;
|
|
12880
|
-
}
|
|
12881
|
-
let text;
|
|
12882
|
-
const conv = convertedFile(kbRoot, ref);
|
|
12883
|
-
try {
|
|
12884
|
-
if (!changed && fs19.existsSync(conv))
|
|
12885
|
-
text = fs19.readFileSync(conv, "utf8");
|
|
12886
|
-
else {
|
|
12887
|
-
text = PASS_THROUGH.has(path19.extname(file).toLowerCase()) ? fs19.readFileSync(file, "utf8") : await converter(file);
|
|
12888
|
-
if (!opts.dryRun) {
|
|
12889
|
-
fs19.mkdirSync(path19.dirname(conv), { recursive: true });
|
|
12890
|
-
fs19.writeFileSync(conv, text);
|
|
12891
|
-
}
|
|
12892
|
-
}
|
|
12893
|
-
} catch (e) {
|
|
12894
|
-
plan.failed.push({ ref, error: e.message.split("\n")[0] });
|
|
12895
|
-
continue;
|
|
12896
|
-
}
|
|
12897
|
-
const all = splitSections(text);
|
|
12898
|
-
const from = changed ? 0 : prior.cursor;
|
|
12899
|
-
const take = all.slice(from, from + budget);
|
|
12900
|
-
budget -= take.length;
|
|
12901
|
-
plan.carriedSections += all.length - from - take.length;
|
|
12902
|
-
plan.sectionCount += take.length;
|
|
12903
|
-
plan.estimatedTokens += Math.ceil(take.reduce((n, s) => n + (s.end - s.start), 0) / CHARS_PER_TOKEN);
|
|
12904
|
-
plan.sources.push({
|
|
12905
|
-
ref,
|
|
12906
|
-
file,
|
|
12907
|
-
converted: conv,
|
|
12908
|
-
sha: stamp.sha,
|
|
12909
|
-
priority: entry.priority,
|
|
12910
|
-
domain: entry.domain,
|
|
12911
|
-
sensitivity: entry.sensitivity,
|
|
12912
|
-
sections: take,
|
|
12913
|
-
totalSections: all.length
|
|
12914
|
-
});
|
|
12915
|
-
if (!opts.dryRun)
|
|
12916
|
-
writeState(kbRoot, { ref, ...stamp, sections: all.length, cursor: from + take.length, priority: entry.priority });
|
|
12917
|
-
}
|
|
12918
|
-
}
|
|
12919
|
-
return plan;
|
|
12920
|
-
}
|
|
12921
|
-
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome2, fileForRef, cacheKey, convertedFile, stampFile, sha256;
|
|
12922
|
-
var init_ingest = __esm({
|
|
12923
|
-
"packages/core/dist/knowledge/ingest.js"() {
|
|
12924
|
-
execFileAsync = promisify2(execFile2);
|
|
12925
|
-
CONVERTED_DIR = ".converted";
|
|
12926
|
-
DEFAULT_MAX_SECTIONS_PER_PASS = 40;
|
|
12927
|
-
CHARS_PER_TOKEN = 4;
|
|
12928
|
-
PASS_THROUGH = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
12929
|
-
SECTION_TARGET_CHARS = 4e3;
|
|
12930
|
-
markitdownConverter = async (file) => {
|
|
12931
|
-
const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
|
|
12932
|
-
return stdout;
|
|
12933
|
-
};
|
|
12934
|
-
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path19.join(os8.homedir(), p.slice(1)) : p;
|
|
12935
|
-
fileForRef = (kbRoot, ref) => path19.resolve(kbRoot, expandHome2(ref));
|
|
12936
|
-
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
12937
|
-
convertedFile = (kbRoot, ref) => path19.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
12938
|
-
stampFile = (kbRoot, ref) => path19.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
12939
|
-
sha256 = (file) => crypto3.createHash("sha256").update(fs19.readFileSync(file)).digest("hex");
|
|
12940
|
-
}
|
|
12941
|
-
});
|
|
12942
|
-
|
|
12943
13033
|
// packages/core/dist/knowledge/match.js
|
|
12944
13034
|
import path20 from "path";
|
|
12945
13035
|
function globMatches(glob, relPath) {
|
|
@@ -13357,6 +13447,13 @@ function ensureGitRepo(dir) {
|
|
|
13357
13447
|
return false;
|
|
13358
13448
|
}
|
|
13359
13449
|
}
|
|
13450
|
+
function ensureKbGitignore(dir) {
|
|
13451
|
+
const file = path23.join(dir, ".gitignore");
|
|
13452
|
+
if (fs22.existsSync(file))
|
|
13453
|
+
return false;
|
|
13454
|
+
fs22.writeFileSync(file, KB_GITIGNORE);
|
|
13455
|
+
return true;
|
|
13456
|
+
}
|
|
13360
13457
|
function findLegacyOverlays(cfg) {
|
|
13361
13458
|
return Object.keys(cfg.projects).filter((p) => fs22.existsSync(legacyOverlay(cfg, p))).sort();
|
|
13362
13459
|
}
|
|
@@ -13411,6 +13508,8 @@ function moveLegacyKbs(cfg, opts = {}) {
|
|
|
13411
13508
|
}
|
|
13412
13509
|
if (ensureGitRepo(to))
|
|
13413
13510
|
notes.push("git init");
|
|
13511
|
+
if (ensureKbGitignore(to))
|
|
13512
|
+
notes.push("wrote .gitignore (raw/, .converted/)");
|
|
13414
13513
|
if (fs22.existsSync(path23.join(to, "index.json")))
|
|
13415
13514
|
notes.push(`index.json holds old paths: run squadrant knowledge reindex ${kb}`);
|
|
13416
13515
|
if (action === "copied")
|
|
@@ -13418,87 +13517,17 @@ function moveLegacyKbs(cfg, opts = {}) {
|
|
|
13418
13517
|
return { kb, from, to, action, ...notes.length ? { note: notes.join("; ") } : {} };
|
|
13419
13518
|
});
|
|
13420
13519
|
}
|
|
13421
|
-
var legacyRoot, legacyOverlay;
|
|
13520
|
+
var legacyRoot, KB_GITIGNORE, legacyOverlay;
|
|
13422
13521
|
var init_migrate = __esm({
|
|
13423
13522
|
"packages/core/dist/knowledge/migrate.js"() {
|
|
13424
13523
|
init_dist();
|
|
13425
13524
|
init_paths();
|
|
13426
13525
|
legacyRoot = (cfg) => path23.join(resolveHome(cfg.hubVault), "knowledge");
|
|
13526
|
+
KB_GITIGNORE = "# squadrant KB defaults: source documents stay local\nraw/\n.converted/\n";
|
|
13427
13527
|
legacyOverlay = (cfg, project) => path23.join(resolveHome(cfg.projects[project].spokeVault), "knowledge", "rules");
|
|
13428
13528
|
}
|
|
13429
13529
|
});
|
|
13430
13530
|
|
|
13431
|
-
// packages/core/dist/knowledge/verify.js
|
|
13432
|
-
function normalizeWithMap(src, keepBreakHyphen = false) {
|
|
13433
|
-
const out = [];
|
|
13434
|
-
const map2 = [];
|
|
13435
|
-
const push = (s, at) => {
|
|
13436
|
-
for (const ch of s) {
|
|
13437
|
-
out.push(ch);
|
|
13438
|
-
map2.push(at);
|
|
13439
|
-
}
|
|
13440
|
-
};
|
|
13441
|
-
let i = 0;
|
|
13442
|
-
while (i < src.length) {
|
|
13443
|
-
const ch = src[i];
|
|
13444
|
-
if (ch === "-" && /^-[ \t]*\r?\n[ \t]*[a-z]/.test(src.slice(i, i + 40)) && i > 0 && /[A-Za-z]/.test(src[i - 1])) {
|
|
13445
|
-
if (keepBreakHyphen)
|
|
13446
|
-
push("-", i);
|
|
13447
|
-
i++;
|
|
13448
|
-
while (/\s/.test(src[i]))
|
|
13449
|
-
i++;
|
|
13450
|
-
continue;
|
|
13451
|
-
}
|
|
13452
|
-
if (/\s/.test(ch)) {
|
|
13453
|
-
const start = i;
|
|
13454
|
-
while (i < src.length && /\s/.test(src[i]))
|
|
13455
|
-
i++;
|
|
13456
|
-
if (out.length && out[out.length - 1] !== " ")
|
|
13457
|
-
push(" ", start);
|
|
13458
|
-
continue;
|
|
13459
|
-
}
|
|
13460
|
-
if (LIGATURES[ch])
|
|
13461
|
-
push(LIGATURES[ch], i);
|
|
13462
|
-
else if (QUOTES[ch])
|
|
13463
|
-
push(QUOTES[ch], i);
|
|
13464
|
-
else if (DASHES.has(ch))
|
|
13465
|
-
push("-", i);
|
|
13466
|
-
else
|
|
13467
|
-
push(ch, i);
|
|
13468
|
-
i++;
|
|
13469
|
-
}
|
|
13470
|
-
while (out.length && out[out.length - 1] === " ") {
|
|
13471
|
-
out.pop();
|
|
13472
|
-
map2.pop();
|
|
13473
|
-
}
|
|
13474
|
-
return { text: out.join(""), map: map2 };
|
|
13475
|
-
}
|
|
13476
|
-
function findQuote(source, quote) {
|
|
13477
|
-
const needle = normalizeText(quote);
|
|
13478
|
-
if (!needle)
|
|
13479
|
-
return null;
|
|
13480
|
-
const views = typeof source === "string" ? normalizedViews(source) : source;
|
|
13481
|
-
for (const hay of views) {
|
|
13482
|
-
const at = hay.text.indexOf(needle);
|
|
13483
|
-
if (at >= 0)
|
|
13484
|
-
return [hay.map[at], hay.map[at + needle.length - 1] + 1];
|
|
13485
|
-
}
|
|
13486
|
-
return null;
|
|
13487
|
-
}
|
|
13488
|
-
var LIGATURES, QUOTES, DASHES, normalizeText, normalizedViews, DOCLING_DROP_THRESHOLD, needsDocling, spansOverlap;
|
|
13489
|
-
var init_verify = __esm({
|
|
13490
|
-
"packages/core/dist/knowledge/verify.js"() {
|
|
13491
|
-
LIGATURES = { "\uFB01": "fi", "\uFB02": "fl", "\uFB00": "ff", "\uFB03": "ffi", "\uFB04": "ffl", "\uFB05": "st", "\uFB06": "st" };
|
|
13492
|
-
QUOTES = { "\u2018": "'", "\u2019": "'", "\u201A": "'", "\u201B": "'", "\u201C": '"', "\u201D": '"', "\u201E": '"', "\u201F": '"' };
|
|
13493
|
-
DASHES = /* @__PURE__ */ new Set(["\u2010", "\u2011", "\u2012", "\u2013", "\u2014", "\u2015", "\u2212"]);
|
|
13494
|
-
normalizeText = (s) => normalizeWithMap(s).text;
|
|
13495
|
-
normalizedViews = (src) => [normalizeWithMap(src), normalizeWithMap(src, true)];
|
|
13496
|
-
DOCLING_DROP_THRESHOLD = 0.2;
|
|
13497
|
-
needsDocling = (dropped, total) => total > 0 && dropped / total > DOCLING_DROP_THRESHOLD;
|
|
13498
|
-
spansOverlap = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
13499
|
-
}
|
|
13500
|
-
});
|
|
13501
|
-
|
|
13502
13531
|
// packages/core/dist/knowledge/anchor.js
|
|
13503
13532
|
import fs23 from "fs";
|
|
13504
13533
|
import path24 from "path";
|
|
@@ -15024,6 +15053,7 @@ __export(dist_exports, {
|
|
|
15024
15053
|
NOISY_RATE: () => NOISY_RATE,
|
|
15025
15054
|
OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
|
|
15026
15055
|
PANE_IDLE_AFTER_MS: () => PANE_IDLE_AFTER_MS,
|
|
15056
|
+
PASS_THROUGH: () => PASS_THROUGH,
|
|
15027
15057
|
PROBE_QUIET_MS: () => PROBE_QUIET_MS,
|
|
15028
15058
|
PROMPT_MIN_SCORE: () => PROMPT_MIN_SCORE,
|
|
15029
15059
|
PROMPT_RULE_CAP: () => PROMPT_RULE_CAP,
|
|
@@ -15163,6 +15193,7 @@ __export(dist_exports, {
|
|
|
15163
15193
|
encodeMsg: () => encodeMsg,
|
|
15164
15194
|
ensureDaemon: () => ensureDaemon,
|
|
15165
15195
|
ensureGitRepo: () => ensureGitRepo,
|
|
15196
|
+
ensureKbGitignore: () => ensureKbGitignore,
|
|
15166
15197
|
ensureSocksDir: () => ensureSocksDir,
|
|
15167
15198
|
escalationsFile: () => escalationsFile,
|
|
15168
15199
|
evaluateCodeConflict: () => evaluateCodeConflict,
|