squadrant 0.26.0 → 0.26.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.
@@ -9288,8 +9288,12 @@ var init_paths = __esm({
9288
9288
 
9289
9289
  // packages/core/dist/knowledge/store.js
9290
9290
  import fs15 from "fs";
9291
+ import os7 from "os";
9291
9292
  import path15 from "path";
9292
9293
  import matter2 from "gray-matter";
9294
+ function duplicateIdProblem(id, ignored, used) {
9295
+ 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.`;
9296
+ }
9293
9297
  function splitStatement(body) {
9294
9298
  const first = body.trim().split(/\n\s*\n/)[0] ?? "";
9295
9299
  return first.replace(/\s+/g, " ").trim();
@@ -9334,7 +9338,7 @@ function loadRulesDir(dir, layer, opts = {}) {
9334
9338
  const fm = parsed.data;
9335
9339
  const prior = seen.get(fm.id);
9336
9340
  if (prior) {
9337
- errors.push({ file, problems: [`duplicate id ${fm.id} (also in ${prior})`] });
9341
+ errors.push({ file, problems: [duplicateIdProblem(fm.id, file, prior)] });
9338
9342
  continue;
9339
9343
  }
9340
9344
  seen.set(fm.id, file);
@@ -9342,7 +9346,65 @@ function loadRulesDir(dir, layer, opts = {}) {
9342
9346
  }
9343
9347
  return { rules, errors };
9344
9348
  }
9345
- var NO_JS_FRONTMATTER;
9349
+ function resolveSourceRef(ref, kbRoot, sources) {
9350
+ const bases = /* @__PURE__ */ new Set([kbRoot]);
9351
+ for (const s of sources) {
9352
+ let d = path15.resolve(kbRoot, expandHome(s.path.split(/[*?[{]/)[0]));
9353
+ for (let i = 0; i < 6 && d !== path15.dirname(d); i++) {
9354
+ d = path15.dirname(d);
9355
+ bases.add(d);
9356
+ }
9357
+ }
9358
+ const cands = [path15.resolve(kbRoot, expandHome(ref)), ...[...bases].map((b) => path15.join(b, ref))];
9359
+ return cands.find((c) => fs15.existsSync(c) && fs15.statSync(c).isFile());
9360
+ }
9361
+ function validateKb(opts) {
9362
+ const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
9363
+ const checks = [];
9364
+ const dups = errors.filter((e) => e.problems.some((p) => p.startsWith("duplicate id")));
9365
+ const invalid = errors.filter((e) => !dups.includes(e));
9366
+ const proposed = rules.filter((r) => path15.relative(opts.rulesDir, r.file).split(path15.sep).includes(PROPOSED_DIR)).length;
9367
+ checks.push({ level: "ok", message: `${rules.length + errors.length} rule files read (${rules.length - proposed} live, ${proposed} proposed parsed OK)` });
9368
+ if (invalid.length)
9369
+ for (const e of invalid)
9370
+ checks.push({ level: "fail", message: `invalid ${e.file}: ${e.problems.join("; ")}` });
9371
+ else
9372
+ checks.push({ level: "ok", message: "no invalid rule files" });
9373
+ if (dups.length)
9374
+ for (const e of dups)
9375
+ checks.push({ level: "fail", message: e.problems.join("; ") });
9376
+ else
9377
+ checks.push({ level: "ok", message: "no duplicate ids" });
9378
+ const cache = /* @__PURE__ */ new Map();
9379
+ let verified = 0, unresolved = 0;
9380
+ for (const r of rules) {
9381
+ r.sources.forEach((src, i) => {
9382
+ const file = resolveSourceRef(src.ref, opts.kbRoot, opts.sources);
9383
+ if (!file) {
9384
+ unresolved++;
9385
+ return;
9386
+ }
9387
+ if (!cache.has(file))
9388
+ cache.set(file, fs15.readFileSync(file, "utf8"));
9389
+ if (cache.get(file).includes(src.quote))
9390
+ verified++;
9391
+ else
9392
+ checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
9393
+ });
9394
+ }
9395
+ if (!checks.some((c) => c.message.startsWith("quote not found")))
9396
+ checks.push({ level: "ok", message: `${verified} source quotes found in their source files` });
9397
+ if (unresolved)
9398
+ checks.push({ level: "skip", message: `${unresolved} source refs not resolvable on this machine, quote not checked` });
9399
+ if (opts.domains) {
9400
+ for (const r of rules) {
9401
+ if (!opts.domains.includes(r.domain))
9402
+ checks.push({ level: "warn", message: `${r.id}: domain '${r.domain}' not in allowed domains [${opts.domains.join(", ")}] (${r.file})` });
9403
+ }
9404
+ }
9405
+ return { checks, ok: !checks.some((c) => c.level === "fail") };
9406
+ }
9407
+ var NO_JS_FRONTMATTER, expandHome;
9346
9408
  var init_store2 = __esm({
9347
9409
  "packages/core/dist/knowledge/store.js"() {
9348
9410
  init_dist();
@@ -9352,6 +9414,7 @@ var init_store2 = __esm({
9352
9414
  throw new Error("only YAML front matter is allowed");
9353
9415
  } } }
9354
9416
  };
9417
+ expandHome = (p) => p === "~" || p.startsWith("~/") ? path15.join(os7.homedir(), p.slice(1)) : p;
9355
9418
  }
9356
9419
  });
9357
9420
 
@@ -9440,7 +9503,7 @@ var init_index_file = __esm({
9440
9503
 
9441
9504
  // packages/core/dist/knowledge/search.js
9442
9505
  function searchRules(rules, query, opts = {}) {
9443
- const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
9506
+ const terms = [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))];
9444
9507
  if (terms.length === 0)
9445
9508
  return [];
9446
9509
  const statuses = opts.statuses ?? DEFAULT_SEARCH_STATUSES;
@@ -9452,30 +9515,45 @@ function searchRules(rules, query, opts = {}) {
9452
9515
  const expanded = lower(rule.triggers?.expanded);
9453
9516
  const when = (rule.triggers?.when ?? "").toLowerCase();
9454
9517
  const statement = rule.statement.toLowerCase();
9518
+ const rationale = rationaleOf(rule);
9455
9519
  const id = rule.id.toLowerCase();
9456
9520
  let score = 0;
9521
+ let matched = 0;
9522
+ let curated = false;
9457
9523
  for (const t of terms) {
9524
+ let s = 0;
9458
9525
  if (id.includes(t))
9459
- score += 3;
9526
+ s += 3;
9527
+ if (keywords.includes(t) || expanded.includes(t))
9528
+ curated = true;
9460
9529
  if (keywords.includes(t))
9461
- score += 3;
9530
+ s += 3;
9462
9531
  if (expanded.includes(t))
9463
- score += 2;
9532
+ s += 3;
9464
9533
  if (when.includes(t))
9465
- score += 2;
9534
+ s += 2;
9466
9535
  if (statement.includes(t))
9467
- score += 1;
9536
+ s += 2;
9537
+ if (rationale.includes(t))
9538
+ s += 1;
9539
+ if (s > 0) {
9540
+ matched++;
9541
+ score += s;
9542
+ }
9468
9543
  }
9469
9544
  if (score > 0)
9470
- hits.push({ rule, score });
9545
+ hits.push({ rule, score, matched, curated });
9471
9546
  }
9472
- return hits.sort((a, b) => b.score - a.score || a.rule.id.localeCompare(b.rule.id));
9547
+ const strong = terms.length >= 2 ? hits.filter((h) => h.matched >= 2 || h.curated) : hits;
9548
+ const out = strong.length ? strong : hits;
9549
+ return out.sort((a, b) => b.score - a.score || a.rule.id.localeCompare(b.rule.id));
9473
9550
  }
9474
- var DEFAULT_SEARCH_STATUSES, lower;
9551
+ var DEFAULT_SEARCH_STATUSES, lower, rationaleOf;
9475
9552
  var init_search = __esm({
9476
9553
  "packages/core/dist/knowledge/search.js"() {
9477
9554
  DEFAULT_SEARCH_STATUSES = ["active", "stale"];
9478
9555
  lower = (xs) => (xs ?? []).map((x) => x.toLowerCase());
9556
+ rationaleOf = (rule) => rule.body.slice(rule.statement.length).toLowerCase();
9479
9557
  }
9480
9558
  });
9481
9559
 
@@ -12698,6 +12776,7 @@ __export(dist_exports, {
12698
12776
  discoverCaptainSurface: () => discoverCaptainSurface,
12699
12777
  discoverLiveOpencodeServer: () => discoverLiveOpencodeServer,
12700
12778
  dispatchToSibling: () => dispatchToSibling,
12779
+ duplicateIdProblem: () => duplicateIdProblem,
12701
12780
  encodeFrame: () => encodeFrame,
12702
12781
  encodeMsg: () => encodeMsg,
12703
12782
  ensureDaemon: () => ensureDaemon,
@@ -12885,6 +12964,7 @@ __export(dist_exports, {
12885
12964
  topicName: () => topicName,
12886
12965
  tryAcquireDaemonLock: () => tryAcquireDaemonLock,
12887
12966
  usageFromJson: () => usageFromJson,
12967
+ validateKb: () => validateKb,
12888
12968
  waitForCaptainDelivery: () => waitForCaptainDelivery,
12889
12969
  waitForWarmup: () => waitForWarmup,
12890
12970
  writeCaptainAddress: () => writeCaptainAddress,
@@ -12949,6 +13029,20 @@ var init_dist2 = __esm({
12949
13029
  }
12950
13030
  });
12951
13031
 
13032
+ // packages/cli/src/lib/suppress-sqlite-warning.ts
13033
+ function isSqliteExperimentalWarning(warning, type2) {
13034
+ const name = typeof warning === "object" && warning !== null ? warning.name : typeof type2 === "string" ? type2 : void 0;
13035
+ const message = typeof warning === "string" ? warning : warning?.message;
13036
+ return name === "ExperimentalWarning" && typeof message === "string" && /SQLite is an experimental feature/i.test(message);
13037
+ }
13038
+ var original = process.emitWarning.bind(process);
13039
+ process.emitWarning = ((warning, ...rest) => {
13040
+ const first = rest[0];
13041
+ const type2 = typeof first === "string" ? first : first?.type;
13042
+ if (isSqliteExperimentalWarning(warning, type2)) return;
13043
+ original(warning, ...rest);
13044
+ });
13045
+
12952
13046
  // packages/cli/src/squadrantd.ts
12953
13047
  init_dist2();
12954
13048
  init_dist2();
@@ -13053,31 +13147,31 @@ import path18 from "path";
13053
13147
  // packages/agents/dist/projection/cursor.js
13054
13148
  import { mkdir, readFile, writeFile } from "fs/promises";
13055
13149
  import path19 from "path";
13056
- import os7 from "os";
13150
+ import os8 from "os";
13057
13151
 
13058
13152
  // packages/agents/dist/projection/codex.js
13059
13153
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
13060
13154
  import path20 from "path";
13061
- import os8 from "os";
13155
+ import os9 from "os";
13062
13156
 
13063
13157
  // packages/agents/dist/projection/gemini.js
13064
13158
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
13065
13159
  import path21 from "path";
13066
- import os9 from "os";
13160
+ import os10 from "os";
13067
13161
 
13068
13162
  // packages/agents/dist/projection/opencode.js
13069
13163
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
13070
13164
  import path22 from "path";
13071
- import os10 from "os";
13165
+ import os11 from "os";
13072
13166
 
13073
13167
  // packages/agents/dist/projection/opencode-skills.js
13074
13168
  import fs21 from "fs";
13075
- import os11 from "os";
13169
+ import os12 from "os";
13076
13170
  import path23 from "path";
13077
13171
  var OPENCODE_SKILL_MARKER = ".squadrant-managed";
13078
13172
  var MARKER_BODY = "squadrant\n";
13079
13173
  function defaultOpencodeSkillsRoot(env = process.env) {
13080
- const configHome = env.XDG_CONFIG_HOME || path23.join(os11.homedir(), ".config");
13174
+ const configHome = env.XDG_CONFIG_HOME || path23.join(os12.homedir(), ".config");
13081
13175
  return path23.join(configHome, "opencode", "skills");
13082
13176
  }
13083
13177
  var SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
@@ -13165,7 +13259,7 @@ function syncShippedOpencodeSkills(opts) {
13165
13259
  // packages/agents/dist/projection/claude.js
13166
13260
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
13167
13261
  import path24 from "path";
13168
- import os12 from "os";
13262
+ import os13 from "os";
13169
13263
 
13170
13264
  // packages/agents/dist/codex/app-server-client.js
13171
13265
  import { EventEmitter } from "events";
@@ -14510,7 +14604,7 @@ var ClaudeReceiptListener = class {
14510
14604
 
14511
14605
  // packages/agents/dist/claude/api-key-approval.js
14512
14606
  import fs22 from "fs";
14513
- import os13 from "os";
14607
+ import os14 from "os";
14514
14608
  import path25 from "path";
14515
14609
 
14516
14610
  // packages/agents/dist/opencode/http-channel.js