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.
- package/dist/index.js +198 -54
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +113 -19
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/plugin/skills/captain-ops/SKILL.md +5 -0
- package/plugin/skills/rules-ops/SKILL.md +56 -0
- package/templates/captain.claude.md +1 -0
- package/templates/captain.generic.md +4 -0
- package/templates/crew.claude.md +4 -0
- package/templates/crew.generic.md +4 -0
- package/templates/crew.opencode.md +4 -0
package/dist/squadrantd.js
CHANGED
|
@@ -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: [
|
|
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
|
-
|
|
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
|
-
|
|
9526
|
+
s += 3;
|
|
9527
|
+
if (keywords.includes(t) || expanded.includes(t))
|
|
9528
|
+
curated = true;
|
|
9460
9529
|
if (keywords.includes(t))
|
|
9461
|
-
|
|
9530
|
+
s += 3;
|
|
9462
9531
|
if (expanded.includes(t))
|
|
9463
|
-
|
|
9532
|
+
s += 3;
|
|
9464
9533
|
if (when.includes(t))
|
|
9465
|
-
|
|
9534
|
+
s += 2;
|
|
9466
9535
|
if (statement.includes(t))
|
|
9467
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
13165
|
+
import os11 from "os";
|
|
13072
13166
|
|
|
13073
13167
|
// packages/agents/dist/projection/opencode-skills.js
|
|
13074
13168
|
import fs21 from "fs";
|
|
13075
|
-
import
|
|
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(
|
|
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
|
|
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
|
|
14607
|
+
import os14 from "os";
|
|
14514
14608
|
import path25 from "path";
|
|
14515
14609
|
|
|
14516
14610
|
// packages/agents/dist/opencode/http-channel.js
|