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/index.js
CHANGED
|
@@ -10341,16 +10341,275 @@ var init_paths = __esm({
|
|
|
10341
10341
|
}
|
|
10342
10342
|
});
|
|
10343
10343
|
|
|
10344
|
-
// packages/core/dist/knowledge/
|
|
10344
|
+
// packages/core/dist/knowledge/ingest.js
|
|
10345
|
+
import crypto3 from "crypto";
|
|
10345
10346
|
import fs15 from "fs";
|
|
10346
10347
|
import os7 from "os";
|
|
10347
10348
|
import path16 from "path";
|
|
10349
|
+
import { execFile as execFile2 } from "child_process";
|
|
10350
|
+
import { promisify as promisify2 } from "util";
|
|
10351
|
+
function refFor(kbRoot, file) {
|
|
10352
|
+
const rel = path16.relative(kbRoot, file);
|
|
10353
|
+
if (rel && !rel.startsWith("..") && !path16.isAbsolute(rel))
|
|
10354
|
+
return rel.split(path16.sep).join("/");
|
|
10355
|
+
const home = os7.homedir();
|
|
10356
|
+
return file.startsWith(home + path16.sep) ? `~/${path16.relative(home, file).split(path16.sep).join("/")}` : file;
|
|
10357
|
+
}
|
|
10358
|
+
function readState2(kbRoot, ref) {
|
|
10359
|
+
try {
|
|
10360
|
+
return JSON.parse(fs15.readFileSync(stampFile(kbRoot, ref), "utf8"));
|
|
10361
|
+
} catch {
|
|
10362
|
+
return null;
|
|
10363
|
+
}
|
|
10364
|
+
}
|
|
10365
|
+
function writeState(kbRoot, st) {
|
|
10366
|
+
fs15.mkdirSync(path16.join(kbRoot, CONVERTED_DIR), { recursive: true });
|
|
10367
|
+
fs15.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
|
|
10368
|
+
}
|
|
10369
|
+
function globToRegExp(glob) {
|
|
10370
|
+
let re = "";
|
|
10371
|
+
for (let i = 0; i < glob.length; i++) {
|
|
10372
|
+
const c = glob[i];
|
|
10373
|
+
if (c === "*") {
|
|
10374
|
+
if (glob[i + 1] === "*") {
|
|
10375
|
+
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
10376
|
+
i += glob[i + 2] === "/" ? 2 : 1;
|
|
10377
|
+
} else
|
|
10378
|
+
re += "[^/]*";
|
|
10379
|
+
} else if (c === "?")
|
|
10380
|
+
re += "[^/]";
|
|
10381
|
+
else
|
|
10382
|
+
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
10383
|
+
}
|
|
10384
|
+
return new RegExp(`^${re}$`);
|
|
10385
|
+
}
|
|
10386
|
+
function walkFiles(dir, out = []) {
|
|
10387
|
+
if (!fs15.existsSync(dir))
|
|
10388
|
+
return out;
|
|
10389
|
+
for (const ent of fs15.readdirSync(dir, { withFileTypes: true })) {
|
|
10390
|
+
if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
|
|
10391
|
+
continue;
|
|
10392
|
+
const full = path16.join(dir, ent.name);
|
|
10393
|
+
if (ent.isDirectory())
|
|
10394
|
+
walkFiles(full, out);
|
|
10395
|
+
else if (ent.isFile())
|
|
10396
|
+
out.push(full);
|
|
10397
|
+
}
|
|
10398
|
+
return out;
|
|
10399
|
+
}
|
|
10400
|
+
function expandSource(kbRoot, entry) {
|
|
10401
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
10402
|
+
if (!/[*?]/.test(entry.path))
|
|
10403
|
+
return fs15.existsSync(abs) && fs15.statSync(abs).isFile() ? [abs] : [];
|
|
10404
|
+
const base = abs.split(/[*?]/)[0];
|
|
10405
|
+
const root = base.endsWith(path16.sep) ? base : path16.dirname(base);
|
|
10406
|
+
const re = globToRegExp(abs.split(path16.sep).join("/"));
|
|
10407
|
+
return walkFiles(root).filter((f) => re.test(f.split(path16.sep).join("/"))).sort();
|
|
10408
|
+
}
|
|
10409
|
+
function detectChange(kbRoot, file) {
|
|
10410
|
+
const ref = refFor(kbRoot, file);
|
|
10411
|
+
const st = fs15.statSync(file);
|
|
10412
|
+
const prior = readState2(kbRoot, ref);
|
|
10413
|
+
if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
|
|
10414
|
+
return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
10415
|
+
}
|
|
10416
|
+
const sha = sha256(file);
|
|
10417
|
+
return { ref, changed: !prior || prior.sha !== sha, stamp: { sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
10418
|
+
}
|
|
10419
|
+
function splitSections(text) {
|
|
10420
|
+
const cuts = [];
|
|
10421
|
+
const re = /^#{1,6}[ \t]+(.+)$/gm;
|
|
10422
|
+
for (let m = re.exec(text); m; m = re.exec(text))
|
|
10423
|
+
cuts.push({ at: m.index, heading: m[1].trim() });
|
|
10424
|
+
if (!cuts.length || cuts[0].at > 0)
|
|
10425
|
+
cuts.unshift({ at: 0 });
|
|
10426
|
+
const spans = [];
|
|
10427
|
+
cuts.forEach((c, i) => {
|
|
10428
|
+
const end = i + 1 < cuts.length ? cuts[i + 1].at : text.length;
|
|
10429
|
+
let start = c.at;
|
|
10430
|
+
while (end - start > SECTION_TARGET_CHARS * 1.5) {
|
|
10431
|
+
const brk = text.indexOf("\n\n", start + SECTION_TARGET_CHARS);
|
|
10432
|
+
if (brk < 0 || brk >= end)
|
|
10433
|
+
break;
|
|
10434
|
+
spans.push({ index: 0, start, end: brk, heading: c.heading });
|
|
10435
|
+
start = brk + 2;
|
|
10436
|
+
}
|
|
10437
|
+
if (text.slice(start, end).trim())
|
|
10438
|
+
spans.push({ index: 0, start, end, heading: c.heading });
|
|
10439
|
+
});
|
|
10440
|
+
return spans.map((s, i) => ({ ...s, index: i }));
|
|
10441
|
+
}
|
|
10442
|
+
async function planIngest(kbRoot, opts) {
|
|
10443
|
+
const converter = opts.converter ?? markitdownConverter;
|
|
10444
|
+
const cap = opts.maxSectionsPerPass ?? DEFAULT_MAX_SECTIONS_PER_PASS;
|
|
10445
|
+
const plan = { sources: [], skipped: [], failed: [], carriedSections: 0, sectionCount: 0, estimatedTokens: 0, existing: opts.existing ?? [] };
|
|
10446
|
+
let budget = cap;
|
|
10447
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10448
|
+
for (const entry of opts.sources) {
|
|
10449
|
+
for (const file of expandSource(kbRoot, entry)) {
|
|
10450
|
+
const { ref, changed, stamp, prior } = detectChange(kbRoot, file);
|
|
10451
|
+
if (seen.has(ref))
|
|
10452
|
+
continue;
|
|
10453
|
+
seen.add(ref);
|
|
10454
|
+
const pending = !!prior && prior.cursor < prior.sections;
|
|
10455
|
+
if (!changed && !pending)
|
|
10456
|
+
continue;
|
|
10457
|
+
if (entry.sensitivity === "local-only" && !opts.localModel) {
|
|
10458
|
+
plan.skipped.push({ ref, reason: "sensitivity: local-only and no local model available" });
|
|
10459
|
+
continue;
|
|
10460
|
+
}
|
|
10461
|
+
if (budget <= 0) {
|
|
10462
|
+
plan.carriedSections += changed ? 1 : prior.sections - prior.cursor;
|
|
10463
|
+
continue;
|
|
10464
|
+
}
|
|
10465
|
+
let text;
|
|
10466
|
+
const conv = convertedFile(kbRoot, ref);
|
|
10467
|
+
try {
|
|
10468
|
+
if (!changed && fs15.existsSync(conv))
|
|
10469
|
+
text = fs15.readFileSync(conv, "utf8");
|
|
10470
|
+
else {
|
|
10471
|
+
text = PASS_THROUGH.has(path16.extname(file).toLowerCase()) ? fs15.readFileSync(file, "utf8") : await converter(file);
|
|
10472
|
+
if (!opts.dryRun) {
|
|
10473
|
+
fs15.mkdirSync(path16.dirname(conv), { recursive: true });
|
|
10474
|
+
fs15.writeFileSync(conv, text);
|
|
10475
|
+
}
|
|
10476
|
+
}
|
|
10477
|
+
} catch (e) {
|
|
10478
|
+
plan.failed.push({ ref, error: e.message.split("\n")[0] });
|
|
10479
|
+
continue;
|
|
10480
|
+
}
|
|
10481
|
+
const all = splitSections(text);
|
|
10482
|
+
const from = changed ? 0 : prior.cursor;
|
|
10483
|
+
const take = all.slice(from, from + budget);
|
|
10484
|
+
budget -= take.length;
|
|
10485
|
+
plan.carriedSections += all.length - from - take.length;
|
|
10486
|
+
plan.sectionCount += take.length;
|
|
10487
|
+
plan.estimatedTokens += Math.ceil(take.reduce((n, s) => n + (s.end - s.start), 0) / CHARS_PER_TOKEN);
|
|
10488
|
+
plan.sources.push({
|
|
10489
|
+
ref,
|
|
10490
|
+
file,
|
|
10491
|
+
converted: conv,
|
|
10492
|
+
sha: stamp.sha,
|
|
10493
|
+
priority: entry.priority,
|
|
10494
|
+
domain: entry.domain,
|
|
10495
|
+
sensitivity: entry.sensitivity,
|
|
10496
|
+
sections: take,
|
|
10497
|
+
totalSections: all.length
|
|
10498
|
+
});
|
|
10499
|
+
if (!opts.dryRun)
|
|
10500
|
+
writeState(kbRoot, { ref, ...stamp, sections: all.length, cursor: from + take.length, priority: entry.priority });
|
|
10501
|
+
}
|
|
10502
|
+
}
|
|
10503
|
+
return plan;
|
|
10504
|
+
}
|
|
10505
|
+
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome, fileForRef, cacheKey, convertedFile, stampFile, sha256;
|
|
10506
|
+
var init_ingest = __esm({
|
|
10507
|
+
"packages/core/dist/knowledge/ingest.js"() {
|
|
10508
|
+
execFileAsync = promisify2(execFile2);
|
|
10509
|
+
CONVERTED_DIR = ".converted";
|
|
10510
|
+
DEFAULT_MAX_SECTIONS_PER_PASS = 40;
|
|
10511
|
+
CHARS_PER_TOKEN = 4;
|
|
10512
|
+
PASS_THROUGH = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
10513
|
+
SECTION_TARGET_CHARS = 4e3;
|
|
10514
|
+
markitdownConverter = async (file) => {
|
|
10515
|
+
const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
|
|
10516
|
+
return stdout;
|
|
10517
|
+
};
|
|
10518
|
+
expandHome = (p) => p === "~" || p.startsWith("~/") ? path16.join(os7.homedir(), p.slice(1)) : p;
|
|
10519
|
+
fileForRef = (kbRoot, ref) => path16.resolve(kbRoot, expandHome(ref));
|
|
10520
|
+
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
10521
|
+
convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
10522
|
+
stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
10523
|
+
sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
|
|
10524
|
+
}
|
|
10525
|
+
});
|
|
10526
|
+
|
|
10527
|
+
// packages/core/dist/knowledge/verify.js
|
|
10528
|
+
function normalizeWithMap(src, keepBreakHyphen = false) {
|
|
10529
|
+
const out = [];
|
|
10530
|
+
const map2 = [];
|
|
10531
|
+
const push = (s, at) => {
|
|
10532
|
+
for (const ch of s) {
|
|
10533
|
+
out.push(ch);
|
|
10534
|
+
map2.push(at);
|
|
10535
|
+
}
|
|
10536
|
+
};
|
|
10537
|
+
let i = 0;
|
|
10538
|
+
while (i < src.length) {
|
|
10539
|
+
const ch = src[i];
|
|
10540
|
+
if (ch === "-" && /^-[ \t]*\r?\n[ \t]*[a-z]/.test(src.slice(i, i + 40)) && i > 0 && /[A-Za-z]/.test(src[i - 1])) {
|
|
10541
|
+
if (keepBreakHyphen)
|
|
10542
|
+
push("-", i);
|
|
10543
|
+
i++;
|
|
10544
|
+
while (/\s/.test(src[i]))
|
|
10545
|
+
i++;
|
|
10546
|
+
continue;
|
|
10547
|
+
}
|
|
10548
|
+
if (/\s/.test(ch)) {
|
|
10549
|
+
const start = i;
|
|
10550
|
+
while (i < src.length && /\s/.test(src[i]))
|
|
10551
|
+
i++;
|
|
10552
|
+
if (out.length && out[out.length - 1] !== " ")
|
|
10553
|
+
push(" ", start);
|
|
10554
|
+
continue;
|
|
10555
|
+
}
|
|
10556
|
+
if (MARKUP.has(ch)) {
|
|
10557
|
+
i++;
|
|
10558
|
+
continue;
|
|
10559
|
+
}
|
|
10560
|
+
if (LIGATURES[ch])
|
|
10561
|
+
push(LIGATURES[ch], i);
|
|
10562
|
+
else if (QUOTES[ch])
|
|
10563
|
+
push(QUOTES[ch], i);
|
|
10564
|
+
else if (DASHES.has(ch))
|
|
10565
|
+
push("-", i);
|
|
10566
|
+
else
|
|
10567
|
+
push(ch, i);
|
|
10568
|
+
i++;
|
|
10569
|
+
}
|
|
10570
|
+
while (out.length && out[out.length - 1] === " ") {
|
|
10571
|
+
out.pop();
|
|
10572
|
+
map2.pop();
|
|
10573
|
+
}
|
|
10574
|
+
return { text: out.join(""), map: map2 };
|
|
10575
|
+
}
|
|
10576
|
+
function findQuote(source, quote) {
|
|
10577
|
+
const needle = normalizeText(quote);
|
|
10578
|
+
if (!needle)
|
|
10579
|
+
return null;
|
|
10580
|
+
const views = typeof source === "string" ? normalizedViews(source) : source;
|
|
10581
|
+
for (const hay of views) {
|
|
10582
|
+
const at = hay.text.indexOf(needle);
|
|
10583
|
+
if (at >= 0)
|
|
10584
|
+
return [hay.map[at], hay.map[at + needle.length - 1] + 1];
|
|
10585
|
+
}
|
|
10586
|
+
return null;
|
|
10587
|
+
}
|
|
10588
|
+
var LIGATURES, QUOTES, DASHES, MARKUP, normalizeText, normalizedViews, DOCLING_DROP_THRESHOLD, needsDocling, spansOverlap;
|
|
10589
|
+
var init_verify = __esm({
|
|
10590
|
+
"packages/core/dist/knowledge/verify.js"() {
|
|
10591
|
+
LIGATURES = { "\uFB01": "fi", "\uFB02": "fl", "\uFB00": "ff", "\uFB03": "ffi", "\uFB04": "ffl", "\uFB05": "st", "\uFB06": "st" };
|
|
10592
|
+
QUOTES = { "\u2018": "'", "\u2019": "'", "\u201A": "'", "\u201B": "'", "\u201C": '"', "\u201D": '"', "\u201E": '"', "\u201F": '"' };
|
|
10593
|
+
DASHES = /* @__PURE__ */ new Set(["\u2010", "\u2011", "\u2012", "\u2013", "\u2014", "\u2015", "\u2212"]);
|
|
10594
|
+
MARKUP = /* @__PURE__ */ new Set(["*", "_", "`", "\\"]);
|
|
10595
|
+
normalizeText = (s) => normalizeWithMap(s).text;
|
|
10596
|
+
normalizedViews = (src) => [normalizeWithMap(src), normalizeWithMap(src, true)];
|
|
10597
|
+
DOCLING_DROP_THRESHOLD = 0.2;
|
|
10598
|
+
needsDocling = (dropped, total) => total > 0 && dropped / total > DOCLING_DROP_THRESHOLD;
|
|
10599
|
+
spansOverlap = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
10600
|
+
}
|
|
10601
|
+
});
|
|
10602
|
+
|
|
10603
|
+
// packages/core/dist/knowledge/store.js
|
|
10604
|
+
import fs16 from "fs";
|
|
10605
|
+
import os8 from "os";
|
|
10606
|
+
import path17 from "path";
|
|
10348
10607
|
import matter2 from "gray-matter";
|
|
10349
10608
|
function duplicateIdProblem(id, ignored, used) {
|
|
10350
10609
|
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.`;
|
|
10351
10610
|
}
|
|
10352
10611
|
function isPendingProposalDup(e, rulesDir) {
|
|
10353
|
-
return e.problems.every((p) => p.startsWith("duplicate id")) &&
|
|
10612
|
+
return e.problems.every((p) => p.startsWith("duplicate id")) && path17.relative(rulesDir, e.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
10354
10613
|
}
|
|
10355
10614
|
function splitStatement(body) {
|
|
10356
10615
|
const first = body.trim().split(/\n\s*\n/)[0] ?? "";
|
|
@@ -10359,8 +10618,8 @@ function splitStatement(body) {
|
|
|
10359
10618
|
function listMarkdown(dir, includeProposed) {
|
|
10360
10619
|
const out = [];
|
|
10361
10620
|
const walk = (d) => {
|
|
10362
|
-
for (const ent of
|
|
10363
|
-
const full =
|
|
10621
|
+
for (const ent of fs16.readdirSync(d, { withFileTypes: true })) {
|
|
10622
|
+
const full = path17.join(d, ent.name);
|
|
10364
10623
|
if (ent.isDirectory()) {
|
|
10365
10624
|
if (ent.name === PROPOSED_DIR && !includeProposed)
|
|
10366
10625
|
continue;
|
|
@@ -10371,11 +10630,11 @@ function listMarkdown(dir, includeProposed) {
|
|
|
10371
10630
|
}
|
|
10372
10631
|
};
|
|
10373
10632
|
walk(dir);
|
|
10374
|
-
const isProposed = (f) =>
|
|
10633
|
+
const isProposed = (f) => path17.relative(dir, f).split(path17.sep).includes(PROPOSED_DIR);
|
|
10375
10634
|
return out.sort((a, b) => Number(isProposed(a)) - Number(isProposed(b)) || (a < b ? -1 : a > b ? 1 : 0));
|
|
10376
10635
|
}
|
|
10377
10636
|
function loadRulesDir(dir, layer, opts = {}) {
|
|
10378
|
-
if (!
|
|
10637
|
+
if (!fs16.existsSync(dir))
|
|
10379
10638
|
return { rules: [], errors: [] };
|
|
10380
10639
|
const rules = [];
|
|
10381
10640
|
const errors = [];
|
|
@@ -10383,7 +10642,7 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
10383
10642
|
for (const file of listMarkdown(dir, opts.includeProposed ?? false)) {
|
|
10384
10643
|
let parsed;
|
|
10385
10644
|
try {
|
|
10386
|
-
parsed = matter2(
|
|
10645
|
+
parsed = matter2(fs16.readFileSync(file, "utf8"), NO_JS_FRONTMATTER);
|
|
10387
10646
|
} catch (e) {
|
|
10388
10647
|
errors.push({ file, problems: [`frontmatter parse error: ${e.message}`] });
|
|
10389
10648
|
continue;
|
|
@@ -10407,14 +10666,14 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
10407
10666
|
function resolveSourceRef(ref, kbRoot, sources) {
|
|
10408
10667
|
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
10409
10668
|
for (const s of sources) {
|
|
10410
|
-
let d =
|
|
10411
|
-
for (let i = 0; i < 6 && d !==
|
|
10412
|
-
d =
|
|
10669
|
+
let d = path17.resolve(kbRoot, expandHome2(s.path.split(/[*?[{]/)[0]));
|
|
10670
|
+
for (let i = 0; i < 6 && d !== path17.dirname(d); i++) {
|
|
10671
|
+
d = path17.dirname(d);
|
|
10413
10672
|
bases.add(d);
|
|
10414
10673
|
}
|
|
10415
10674
|
}
|
|
10416
|
-
const cands = [
|
|
10417
|
-
return cands.find((c) =>
|
|
10675
|
+
const cands = [path17.resolve(kbRoot, expandHome2(ref)), ...[...bases].map((b) => path17.join(b, ref))];
|
|
10676
|
+
return cands.find((c) => fs16.existsSync(c) && fs16.statSync(c).isFile());
|
|
10418
10677
|
}
|
|
10419
10678
|
function validateKb(opts) {
|
|
10420
10679
|
const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
|
|
@@ -10422,7 +10681,7 @@ function validateKb(opts) {
|
|
|
10422
10681
|
const dups = errors.filter((e) => e.problems.some((p) => p.startsWith("duplicate id")) && !isPendingProposalDup(e, opts.rulesDir));
|
|
10423
10682
|
const pendingDups = errors.filter((e) => isPendingProposalDup(e, opts.rulesDir)).length;
|
|
10424
10683
|
const invalid = errors.filter((e) => !dups.includes(e) && !isPendingProposalDup(e, opts.rulesDir));
|
|
10425
|
-
const proposed = rules.filter((r) =>
|
|
10684
|
+
const proposed = rules.filter((r) => path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR)).length;
|
|
10426
10685
|
checks.push({ level: "ok", message: `${rules.length + errors.length} rule files read (${rules.length - proposed} live, ${proposed + pendingDups} proposed parsed OK)` });
|
|
10427
10686
|
if (invalid.length)
|
|
10428
10687
|
for (const e of invalid)
|
|
@@ -10435,7 +10694,7 @@ function validateKb(opts) {
|
|
|
10435
10694
|
else
|
|
10436
10695
|
checks.push({ level: "ok", message: "no duplicate ids" });
|
|
10437
10696
|
const cache = /* @__PURE__ */ new Map();
|
|
10438
|
-
let verified = 0, unresolved = 0;
|
|
10697
|
+
let verified = 0, unresolved = 0, notIngested = 0;
|
|
10439
10698
|
for (const r of rules) {
|
|
10440
10699
|
r.sources.forEach((src, i) => {
|
|
10441
10700
|
const file = resolveSourceRef(src.ref, opts.kbRoot, opts.sources);
|
|
@@ -10443,16 +10702,28 @@ function validateKb(opts) {
|
|
|
10443
10702
|
unresolved++;
|
|
10444
10703
|
return;
|
|
10445
10704
|
}
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
|
|
10705
|
+
const key = `${src.ref}\0${file}`;
|
|
10706
|
+
if (!cache.has(key)) {
|
|
10707
|
+
const conv = readState2(opts.kbRoot, src.ref) ? convertedFile(opts.kbRoot, src.ref) : null;
|
|
10708
|
+
const cached = !!conv && fs16.existsSync(conv);
|
|
10709
|
+
cache.set(key, {
|
|
10710
|
+
hay: normalizedViews(fs16.readFileSync(cached ? conv : file, "utf8")),
|
|
10711
|
+
convertible: !cached && !PASS_THROUGH.has(path17.extname(file).toLowerCase())
|
|
10712
|
+
});
|
|
10713
|
+
}
|
|
10714
|
+
const { hay, convertible } = cache.get(key);
|
|
10715
|
+
if (findQuote(hay, src.quote))
|
|
10449
10716
|
verified++;
|
|
10717
|
+
else if (convertible)
|
|
10718
|
+
notIngested++;
|
|
10450
10719
|
else
|
|
10451
10720
|
checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
|
|
10452
10721
|
});
|
|
10453
10722
|
}
|
|
10454
10723
|
if (!checks.some((c) => c.message.startsWith("quote not found")))
|
|
10455
10724
|
checks.push({ level: "ok", message: `${verified} source quotes found in their source files` });
|
|
10725
|
+
if (notIngested)
|
|
10726
|
+
checks.push({ level: "skip", message: `${notIngested} source refs need conversion but have no .converted cache, quote not checked (run \`squadrant knowledge ingest <kb>\`)` });
|
|
10456
10727
|
if (unresolved)
|
|
10457
10728
|
checks.push({ level: "skip", message: `${unresolved} source refs not resolvable on this machine, quote not checked` });
|
|
10458
10729
|
if (opts.domains) {
|
|
@@ -10463,22 +10734,24 @@ function validateKb(opts) {
|
|
|
10463
10734
|
}
|
|
10464
10735
|
return { checks, ok: !checks.some((c) => c.level === "fail") };
|
|
10465
10736
|
}
|
|
10466
|
-
var NO_JS_FRONTMATTER,
|
|
10737
|
+
var NO_JS_FRONTMATTER, expandHome2;
|
|
10467
10738
|
var init_store2 = __esm({
|
|
10468
10739
|
"packages/core/dist/knowledge/store.js"() {
|
|
10469
10740
|
init_dist();
|
|
10741
|
+
init_ingest();
|
|
10470
10742
|
init_paths();
|
|
10743
|
+
init_verify();
|
|
10471
10744
|
NO_JS_FRONTMATTER = {
|
|
10472
10745
|
engines: { javascript: { parse: () => {
|
|
10473
10746
|
throw new Error("only YAML front matter is allowed");
|
|
10474
10747
|
} } }
|
|
10475
10748
|
};
|
|
10476
|
-
|
|
10749
|
+
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path17.join(os8.homedir(), p.slice(1)) : p;
|
|
10477
10750
|
}
|
|
10478
10751
|
});
|
|
10479
10752
|
|
|
10480
10753
|
// packages/core/dist/knowledge/layers.js
|
|
10481
|
-
import
|
|
10754
|
+
import fs17 from "fs";
|
|
10482
10755
|
function loadKbRules(cfg, kb, opts = {}) {
|
|
10483
10756
|
return loadRulesDir(kbRulesDir(cfg, kb), `kb:${kb}`, opts);
|
|
10484
10757
|
}
|
|
@@ -10490,7 +10763,7 @@ function resolveProjectRules(cfg, project, opts = {}) {
|
|
|
10490
10763
|
const errors = [];
|
|
10491
10764
|
const warnings = [];
|
|
10492
10765
|
for (const kb of subscribedKbs(cfg, project)) {
|
|
10493
|
-
if (!
|
|
10766
|
+
if (!fs17.existsSync(kbDir(cfg, kb))) {
|
|
10494
10767
|
warnings.push(`knowledge base '${kb}' not found (run: squadrant knowledge init ${kb})`);
|
|
10495
10768
|
continue;
|
|
10496
10769
|
}
|
|
@@ -10528,8 +10801,8 @@ var init_layers = __esm({
|
|
|
10528
10801
|
});
|
|
10529
10802
|
|
|
10530
10803
|
// packages/core/dist/knowledge/index-file.js
|
|
10531
|
-
import
|
|
10532
|
-
import
|
|
10804
|
+
import fs18 from "fs";
|
|
10805
|
+
import path18 from "path";
|
|
10533
10806
|
function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
|
|
10534
10807
|
return {
|
|
10535
10808
|
kb,
|
|
@@ -10538,18 +10811,18 @@ function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
|
|
|
10538
10811
|
};
|
|
10539
10812
|
}
|
|
10540
10813
|
function writeIndex(kbRoot, index) {
|
|
10541
|
-
const file =
|
|
10814
|
+
const file = path18.join(kbRoot, "index.json");
|
|
10542
10815
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
10543
|
-
|
|
10544
|
-
|
|
10816
|
+
fs18.writeFileSync(tmp, JSON.stringify(index, null, 2) + "\n");
|
|
10817
|
+
fs18.renameSync(tmp, file);
|
|
10545
10818
|
return file;
|
|
10546
10819
|
}
|
|
10547
10820
|
function readIndex(kbRoot, kb) {
|
|
10548
|
-
const file =
|
|
10549
|
-
if (!
|
|
10821
|
+
const file = path18.join(kbRoot, "index.json");
|
|
10822
|
+
if (!fs18.existsSync(file))
|
|
10550
10823
|
return { index: null, problem: `index.json missing for kb '${kb}'` };
|
|
10551
10824
|
try {
|
|
10552
|
-
const index = JSON.parse(
|
|
10825
|
+
const index = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
10553
10826
|
if (!Array.isArray(index.rules))
|
|
10554
10827
|
return { index: null, problem: `index.json corrupt for kb '${kb}' (no rules array)` };
|
|
10555
10828
|
return { index };
|
|
@@ -13644,15 +13917,15 @@ var init_js_yaml = __esm({
|
|
|
13644
13917
|
});
|
|
13645
13918
|
|
|
13646
13919
|
// packages/core/dist/knowledge/sources.js
|
|
13647
|
-
import
|
|
13648
|
-
import
|
|
13920
|
+
import fs19 from "fs";
|
|
13921
|
+
import path19 from "path";
|
|
13649
13922
|
function loadSources(kbRoot) {
|
|
13650
|
-
const file =
|
|
13651
|
-
if (!
|
|
13923
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
13924
|
+
if (!fs19.existsSync(file))
|
|
13652
13925
|
return { sources: [], errors: [] };
|
|
13653
13926
|
let data;
|
|
13654
13927
|
try {
|
|
13655
|
-
data = yaml.load(
|
|
13928
|
+
data = yaml.load(fs19.readFileSync(file, "utf8"));
|
|
13656
13929
|
} catch (e) {
|
|
13657
13930
|
return { sources: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
13658
13931
|
}
|
|
@@ -13690,189 +13963,6 @@ var init_sources = __esm({
|
|
|
13690
13963
|
}
|
|
13691
13964
|
});
|
|
13692
13965
|
|
|
13693
|
-
// packages/core/dist/knowledge/ingest.js
|
|
13694
|
-
import crypto3 from "crypto";
|
|
13695
|
-
import fs19 from "fs";
|
|
13696
|
-
import os8 from "os";
|
|
13697
|
-
import path19 from "path";
|
|
13698
|
-
import { execFile as execFile2 } from "child_process";
|
|
13699
|
-
import { promisify as promisify2 } from "util";
|
|
13700
|
-
function refFor(kbRoot, file) {
|
|
13701
|
-
const rel = path19.relative(kbRoot, file);
|
|
13702
|
-
if (rel && !rel.startsWith("..") && !path19.isAbsolute(rel))
|
|
13703
|
-
return rel.split(path19.sep).join("/");
|
|
13704
|
-
const home = os8.homedir();
|
|
13705
|
-
return file.startsWith(home + path19.sep) ? `~/${path19.relative(home, file).split(path19.sep).join("/")}` : file;
|
|
13706
|
-
}
|
|
13707
|
-
function readState2(kbRoot, ref) {
|
|
13708
|
-
try {
|
|
13709
|
-
return JSON.parse(fs19.readFileSync(stampFile(kbRoot, ref), "utf8"));
|
|
13710
|
-
} catch {
|
|
13711
|
-
return null;
|
|
13712
|
-
}
|
|
13713
|
-
}
|
|
13714
|
-
function writeState(kbRoot, st) {
|
|
13715
|
-
fs19.mkdirSync(path19.join(kbRoot, CONVERTED_DIR), { recursive: true });
|
|
13716
|
-
fs19.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
|
|
13717
|
-
}
|
|
13718
|
-
function globToRegExp(glob) {
|
|
13719
|
-
let re = "";
|
|
13720
|
-
for (let i = 0; i < glob.length; i++) {
|
|
13721
|
-
const c = glob[i];
|
|
13722
|
-
if (c === "*") {
|
|
13723
|
-
if (glob[i + 1] === "*") {
|
|
13724
|
-
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
13725
|
-
i += glob[i + 2] === "/" ? 2 : 1;
|
|
13726
|
-
} else
|
|
13727
|
-
re += "[^/]*";
|
|
13728
|
-
} else if (c === "?")
|
|
13729
|
-
re += "[^/]";
|
|
13730
|
-
else
|
|
13731
|
-
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
13732
|
-
}
|
|
13733
|
-
return new RegExp(`^${re}$`);
|
|
13734
|
-
}
|
|
13735
|
-
function walkFiles(dir, out = []) {
|
|
13736
|
-
if (!fs19.existsSync(dir))
|
|
13737
|
-
return out;
|
|
13738
|
-
for (const ent of fs19.readdirSync(dir, { withFileTypes: true })) {
|
|
13739
|
-
if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
|
|
13740
|
-
continue;
|
|
13741
|
-
const full = path19.join(dir, ent.name);
|
|
13742
|
-
if (ent.isDirectory())
|
|
13743
|
-
walkFiles(full, out);
|
|
13744
|
-
else if (ent.isFile())
|
|
13745
|
-
out.push(full);
|
|
13746
|
-
}
|
|
13747
|
-
return out;
|
|
13748
|
-
}
|
|
13749
|
-
function expandSource(kbRoot, entry) {
|
|
13750
|
-
const abs = path19.resolve(kbRoot, expandHome2(entry.path));
|
|
13751
|
-
if (!/[*?]/.test(entry.path))
|
|
13752
|
-
return fs19.existsSync(abs) && fs19.statSync(abs).isFile() ? [abs] : [];
|
|
13753
|
-
const base = abs.split(/[*?]/)[0];
|
|
13754
|
-
const root = base.endsWith(path19.sep) ? base : path19.dirname(base);
|
|
13755
|
-
const re = globToRegExp(abs.split(path19.sep).join("/"));
|
|
13756
|
-
return walkFiles(root).filter((f) => re.test(f.split(path19.sep).join("/"))).sort();
|
|
13757
|
-
}
|
|
13758
|
-
function detectChange(kbRoot, file) {
|
|
13759
|
-
const ref = refFor(kbRoot, file);
|
|
13760
|
-
const st = fs19.statSync(file);
|
|
13761
|
-
const prior = readState2(kbRoot, ref);
|
|
13762
|
-
if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
|
|
13763
|
-
return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
13764
|
-
}
|
|
13765
|
-
const sha = sha256(file);
|
|
13766
|
-
return { ref, changed: !prior || prior.sha !== sha, stamp: { sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
13767
|
-
}
|
|
13768
|
-
function splitSections(text) {
|
|
13769
|
-
const cuts = [];
|
|
13770
|
-
const re = /^#{1,6}[ \t]+(.+)$/gm;
|
|
13771
|
-
for (let m = re.exec(text); m; m = re.exec(text))
|
|
13772
|
-
cuts.push({ at: m.index, heading: m[1].trim() });
|
|
13773
|
-
if (!cuts.length || cuts[0].at > 0)
|
|
13774
|
-
cuts.unshift({ at: 0 });
|
|
13775
|
-
const spans = [];
|
|
13776
|
-
cuts.forEach((c, i) => {
|
|
13777
|
-
const end = i + 1 < cuts.length ? cuts[i + 1].at : text.length;
|
|
13778
|
-
let start = c.at;
|
|
13779
|
-
while (end - start > SECTION_TARGET_CHARS * 1.5) {
|
|
13780
|
-
const brk = text.indexOf("\n\n", start + SECTION_TARGET_CHARS);
|
|
13781
|
-
if (brk < 0 || brk >= end)
|
|
13782
|
-
break;
|
|
13783
|
-
spans.push({ index: 0, start, end: brk, heading: c.heading });
|
|
13784
|
-
start = brk + 2;
|
|
13785
|
-
}
|
|
13786
|
-
if (text.slice(start, end).trim())
|
|
13787
|
-
spans.push({ index: 0, start, end, heading: c.heading });
|
|
13788
|
-
});
|
|
13789
|
-
return spans.map((s, i) => ({ ...s, index: i }));
|
|
13790
|
-
}
|
|
13791
|
-
async function planIngest(kbRoot, opts) {
|
|
13792
|
-
const converter = opts.converter ?? markitdownConverter;
|
|
13793
|
-
const cap = opts.maxSectionsPerPass ?? DEFAULT_MAX_SECTIONS_PER_PASS;
|
|
13794
|
-
const plan = { sources: [], skipped: [], failed: [], carriedSections: 0, sectionCount: 0, estimatedTokens: 0, existing: opts.existing ?? [] };
|
|
13795
|
-
let budget = cap;
|
|
13796
|
-
const seen = /* @__PURE__ */ new Set();
|
|
13797
|
-
for (const entry of opts.sources) {
|
|
13798
|
-
for (const file of expandSource(kbRoot, entry)) {
|
|
13799
|
-
const { ref, changed, stamp, prior } = detectChange(kbRoot, file);
|
|
13800
|
-
if (seen.has(ref))
|
|
13801
|
-
continue;
|
|
13802
|
-
seen.add(ref);
|
|
13803
|
-
const pending = !!prior && prior.cursor < prior.sections;
|
|
13804
|
-
if (!changed && !pending)
|
|
13805
|
-
continue;
|
|
13806
|
-
if (entry.sensitivity === "local-only" && !opts.localModel) {
|
|
13807
|
-
plan.skipped.push({ ref, reason: "sensitivity: local-only and no local model available" });
|
|
13808
|
-
continue;
|
|
13809
|
-
}
|
|
13810
|
-
if (budget <= 0) {
|
|
13811
|
-
plan.carriedSections += changed ? 1 : prior.sections - prior.cursor;
|
|
13812
|
-
continue;
|
|
13813
|
-
}
|
|
13814
|
-
let text;
|
|
13815
|
-
const conv = convertedFile(kbRoot, ref);
|
|
13816
|
-
try {
|
|
13817
|
-
if (!changed && fs19.existsSync(conv))
|
|
13818
|
-
text = fs19.readFileSync(conv, "utf8");
|
|
13819
|
-
else {
|
|
13820
|
-
text = PASS_THROUGH.has(path19.extname(file).toLowerCase()) ? fs19.readFileSync(file, "utf8") : await converter(file);
|
|
13821
|
-
if (!opts.dryRun) {
|
|
13822
|
-
fs19.mkdirSync(path19.dirname(conv), { recursive: true });
|
|
13823
|
-
fs19.writeFileSync(conv, text);
|
|
13824
|
-
}
|
|
13825
|
-
}
|
|
13826
|
-
} catch (e) {
|
|
13827
|
-
plan.failed.push({ ref, error: e.message.split("\n")[0] });
|
|
13828
|
-
continue;
|
|
13829
|
-
}
|
|
13830
|
-
const all = splitSections(text);
|
|
13831
|
-
const from = changed ? 0 : prior.cursor;
|
|
13832
|
-
const take = all.slice(from, from + budget);
|
|
13833
|
-
budget -= take.length;
|
|
13834
|
-
plan.carriedSections += all.length - from - take.length;
|
|
13835
|
-
plan.sectionCount += take.length;
|
|
13836
|
-
plan.estimatedTokens += Math.ceil(take.reduce((n, s) => n + (s.end - s.start), 0) / CHARS_PER_TOKEN);
|
|
13837
|
-
plan.sources.push({
|
|
13838
|
-
ref,
|
|
13839
|
-
file,
|
|
13840
|
-
converted: conv,
|
|
13841
|
-
sha: stamp.sha,
|
|
13842
|
-
priority: entry.priority,
|
|
13843
|
-
domain: entry.domain,
|
|
13844
|
-
sensitivity: entry.sensitivity,
|
|
13845
|
-
sections: take,
|
|
13846
|
-
totalSections: all.length
|
|
13847
|
-
});
|
|
13848
|
-
if (!opts.dryRun)
|
|
13849
|
-
writeState(kbRoot, { ref, ...stamp, sections: all.length, cursor: from + take.length, priority: entry.priority });
|
|
13850
|
-
}
|
|
13851
|
-
}
|
|
13852
|
-
return plan;
|
|
13853
|
-
}
|
|
13854
|
-
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome2, fileForRef, cacheKey, convertedFile, stampFile, sha256;
|
|
13855
|
-
var init_ingest = __esm({
|
|
13856
|
-
"packages/core/dist/knowledge/ingest.js"() {
|
|
13857
|
-
execFileAsync = promisify2(execFile2);
|
|
13858
|
-
CONVERTED_DIR = ".converted";
|
|
13859
|
-
DEFAULT_MAX_SECTIONS_PER_PASS = 40;
|
|
13860
|
-
CHARS_PER_TOKEN = 4;
|
|
13861
|
-
PASS_THROUGH = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
13862
|
-
SECTION_TARGET_CHARS = 4e3;
|
|
13863
|
-
markitdownConverter = async (file) => {
|
|
13864
|
-
const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
|
|
13865
|
-
return stdout;
|
|
13866
|
-
};
|
|
13867
|
-
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path19.join(os8.homedir(), p.slice(1)) : p;
|
|
13868
|
-
fileForRef = (kbRoot, ref) => path19.resolve(kbRoot, expandHome2(ref));
|
|
13869
|
-
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
13870
|
-
convertedFile = (kbRoot, ref) => path19.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
13871
|
-
stampFile = (kbRoot, ref) => path19.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
13872
|
-
sha256 = (file) => crypto3.createHash("sha256").update(fs19.readFileSync(file)).digest("hex");
|
|
13873
|
-
}
|
|
13874
|
-
});
|
|
13875
|
-
|
|
13876
13966
|
// packages/core/dist/knowledge/match.js
|
|
13877
13967
|
import path20 from "path";
|
|
13878
13968
|
function globMatches(glob, relPath) {
|
|
@@ -14290,6 +14380,13 @@ function ensureGitRepo(dir) {
|
|
|
14290
14380
|
return false;
|
|
14291
14381
|
}
|
|
14292
14382
|
}
|
|
14383
|
+
function ensureKbGitignore(dir) {
|
|
14384
|
+
const file = path23.join(dir, ".gitignore");
|
|
14385
|
+
if (fs22.existsSync(file))
|
|
14386
|
+
return false;
|
|
14387
|
+
fs22.writeFileSync(file, KB_GITIGNORE);
|
|
14388
|
+
return true;
|
|
14389
|
+
}
|
|
14293
14390
|
function findLegacyOverlays(cfg) {
|
|
14294
14391
|
return Object.keys(cfg.projects).filter((p) => fs22.existsSync(legacyOverlay(cfg, p))).sort();
|
|
14295
14392
|
}
|
|
@@ -14344,6 +14441,8 @@ function moveLegacyKbs(cfg, opts = {}) {
|
|
|
14344
14441
|
}
|
|
14345
14442
|
if (ensureGitRepo(to))
|
|
14346
14443
|
notes.push("git init");
|
|
14444
|
+
if (ensureKbGitignore(to))
|
|
14445
|
+
notes.push("wrote .gitignore (raw/, .converted/)");
|
|
14347
14446
|
if (fs22.existsSync(path23.join(to, "index.json")))
|
|
14348
14447
|
notes.push(`index.json holds old paths: run squadrant knowledge reindex ${kb}`);
|
|
14349
14448
|
if (action === "copied")
|
|
@@ -14351,87 +14450,17 @@ function moveLegacyKbs(cfg, opts = {}) {
|
|
|
14351
14450
|
return { kb, from, to, action, ...notes.length ? { note: notes.join("; ") } : {} };
|
|
14352
14451
|
});
|
|
14353
14452
|
}
|
|
14354
|
-
var legacyRoot, legacyOverlay;
|
|
14453
|
+
var legacyRoot, KB_GITIGNORE, legacyOverlay;
|
|
14355
14454
|
var init_migrate = __esm({
|
|
14356
14455
|
"packages/core/dist/knowledge/migrate.js"() {
|
|
14357
14456
|
init_dist();
|
|
14358
14457
|
init_paths();
|
|
14359
14458
|
legacyRoot = (cfg) => path23.join(resolveHome(cfg.hubVault), "knowledge");
|
|
14459
|
+
KB_GITIGNORE = "# squadrant KB defaults: source documents stay local\nraw/\n.converted/\n";
|
|
14360
14460
|
legacyOverlay = (cfg, project) => path23.join(resolveHome(cfg.projects[project].spokeVault), "knowledge", "rules");
|
|
14361
14461
|
}
|
|
14362
14462
|
});
|
|
14363
14463
|
|
|
14364
|
-
// packages/core/dist/knowledge/verify.js
|
|
14365
|
-
function normalizeWithMap(src, keepBreakHyphen = false) {
|
|
14366
|
-
const out = [];
|
|
14367
|
-
const map2 = [];
|
|
14368
|
-
const push = (s, at) => {
|
|
14369
|
-
for (const ch of s) {
|
|
14370
|
-
out.push(ch);
|
|
14371
|
-
map2.push(at);
|
|
14372
|
-
}
|
|
14373
|
-
};
|
|
14374
|
-
let i = 0;
|
|
14375
|
-
while (i < src.length) {
|
|
14376
|
-
const ch = src[i];
|
|
14377
|
-
if (ch === "-" && /^-[ \t]*\r?\n[ \t]*[a-z]/.test(src.slice(i, i + 40)) && i > 0 && /[A-Za-z]/.test(src[i - 1])) {
|
|
14378
|
-
if (keepBreakHyphen)
|
|
14379
|
-
push("-", i);
|
|
14380
|
-
i++;
|
|
14381
|
-
while (/\s/.test(src[i]))
|
|
14382
|
-
i++;
|
|
14383
|
-
continue;
|
|
14384
|
-
}
|
|
14385
|
-
if (/\s/.test(ch)) {
|
|
14386
|
-
const start = i;
|
|
14387
|
-
while (i < src.length && /\s/.test(src[i]))
|
|
14388
|
-
i++;
|
|
14389
|
-
if (out.length && out[out.length - 1] !== " ")
|
|
14390
|
-
push(" ", start);
|
|
14391
|
-
continue;
|
|
14392
|
-
}
|
|
14393
|
-
if (LIGATURES[ch])
|
|
14394
|
-
push(LIGATURES[ch], i);
|
|
14395
|
-
else if (QUOTES[ch])
|
|
14396
|
-
push(QUOTES[ch], i);
|
|
14397
|
-
else if (DASHES.has(ch))
|
|
14398
|
-
push("-", i);
|
|
14399
|
-
else
|
|
14400
|
-
push(ch, i);
|
|
14401
|
-
i++;
|
|
14402
|
-
}
|
|
14403
|
-
while (out.length && out[out.length - 1] === " ") {
|
|
14404
|
-
out.pop();
|
|
14405
|
-
map2.pop();
|
|
14406
|
-
}
|
|
14407
|
-
return { text: out.join(""), map: map2 };
|
|
14408
|
-
}
|
|
14409
|
-
function findQuote(source, quote) {
|
|
14410
|
-
const needle = normalizeText(quote);
|
|
14411
|
-
if (!needle)
|
|
14412
|
-
return null;
|
|
14413
|
-
const views = typeof source === "string" ? normalizedViews(source) : source;
|
|
14414
|
-
for (const hay of views) {
|
|
14415
|
-
const at = hay.text.indexOf(needle);
|
|
14416
|
-
if (at >= 0)
|
|
14417
|
-
return [hay.map[at], hay.map[at + needle.length - 1] + 1];
|
|
14418
|
-
}
|
|
14419
|
-
return null;
|
|
14420
|
-
}
|
|
14421
|
-
var LIGATURES, QUOTES, DASHES, normalizeText, normalizedViews, DOCLING_DROP_THRESHOLD, needsDocling, spansOverlap;
|
|
14422
|
-
var init_verify = __esm({
|
|
14423
|
-
"packages/core/dist/knowledge/verify.js"() {
|
|
14424
|
-
LIGATURES = { "\uFB01": "fi", "\uFB02": "fl", "\uFB00": "ff", "\uFB03": "ffi", "\uFB04": "ffl", "\uFB05": "st", "\uFB06": "st" };
|
|
14425
|
-
QUOTES = { "\u2018": "'", "\u2019": "'", "\u201A": "'", "\u201B": "'", "\u201C": '"', "\u201D": '"', "\u201E": '"', "\u201F": '"' };
|
|
14426
|
-
DASHES = /* @__PURE__ */ new Set(["\u2010", "\u2011", "\u2012", "\u2013", "\u2014", "\u2015", "\u2212"]);
|
|
14427
|
-
normalizeText = (s) => normalizeWithMap(s).text;
|
|
14428
|
-
normalizedViews = (src) => [normalizeWithMap(src), normalizeWithMap(src, true)];
|
|
14429
|
-
DOCLING_DROP_THRESHOLD = 0.2;
|
|
14430
|
-
needsDocling = (dropped, total) => total > 0 && dropped / total > DOCLING_DROP_THRESHOLD;
|
|
14431
|
-
spansOverlap = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
14432
|
-
}
|
|
14433
|
-
});
|
|
14434
|
-
|
|
14435
14464
|
// packages/core/dist/knowledge/anchor.js
|
|
14436
14465
|
import fs23 from "fs";
|
|
14437
14466
|
import path24 from "path";
|
|
@@ -15957,6 +15986,7 @@ __export(dist_exports2, {
|
|
|
15957
15986
|
NOISY_RATE: () => NOISY_RATE,
|
|
15958
15987
|
OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
|
|
15959
15988
|
PANE_IDLE_AFTER_MS: () => PANE_IDLE_AFTER_MS,
|
|
15989
|
+
PASS_THROUGH: () => PASS_THROUGH,
|
|
15960
15990
|
PROBE_QUIET_MS: () => PROBE_QUIET_MS,
|
|
15961
15991
|
PROMPT_MIN_SCORE: () => PROMPT_MIN_SCORE,
|
|
15962
15992
|
PROMPT_RULE_CAP: () => PROMPT_RULE_CAP,
|
|
@@ -16096,6 +16126,7 @@ __export(dist_exports2, {
|
|
|
16096
16126
|
encodeMsg: () => encodeMsg,
|
|
16097
16127
|
ensureDaemon: () => ensureDaemon,
|
|
16098
16128
|
ensureGitRepo: () => ensureGitRepo,
|
|
16129
|
+
ensureKbGitignore: () => ensureKbGitignore,
|
|
16099
16130
|
ensureSocksDir: () => ensureSocksDir,
|
|
16100
16131
|
escalationsFile: () => escalationsFile,
|
|
16101
16132
|
evaluateCodeConflict: () => evaluateCodeConflict,
|
|
@@ -30670,6 +30701,7 @@ function runKnowledgeInit(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30670
30701
|
created.push("index.json");
|
|
30671
30702
|
}
|
|
30672
30703
|
if (ensureGitRepo(dir)) created.push(".git");
|
|
30704
|
+
if (ensureKbGitignore(dir)) created.push(".gitignore");
|
|
30673
30705
|
if (!kbConfigs(cfg)[kb]) {
|
|
30674
30706
|
cfg.knowledgeBases = { ...cfg.knowledgeBases ?? {}, [kb]: {} };
|
|
30675
30707
|
saveConfig(cfg, configPath);
|
|
@@ -30700,6 +30732,7 @@ var knowledgeCommand = new Command39("knowledge").description("Manage rules know
|
|
|
30700
30732
|
knowledgeCommand.command("init <kb>").description("Create a knowledge base (its own git repo) under ~/squadrant/kb/<kb>/").action((kb) => {
|
|
30701
30733
|
const { dir, created } = runKnowledgeInit(kb);
|
|
30702
30734
|
console.log(created.length ? chalk38.green(`Initialised ${dir} (${created.join(", ")})`) : `Already initialised: ${dir}`);
|
|
30735
|
+
console.log(chalk38.dim("raw/ and .converted/ are git-ignored by default (edit .gitignore to opt in)."));
|
|
30703
30736
|
console.log(chalk38.dim(KNOWLEDGE_PRIVACY_NOTICE));
|
|
30704
30737
|
});
|
|
30705
30738
|
knowledgeCommand.command("subscribe <kb>").description("Subscribe a project to a knowledge base").requiredOption("--project <name>", "project to subscribe").action((kb, opts) => {
|