squadrant 0.26.0 → 0.26.2

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 CHANGED
@@ -594,22 +594,22 @@ function defaultCmuxConfigPath() {
594
594
  return join(homedir(), ".config", "cmux", "cmux.json");
595
595
  }
596
596
  function ensureSocketAutomation(opts = {}) {
597
- const path45 = opts.path ?? defaultCmuxConfigPath();
598
- if (!existsSync(path45)) {
599
- mkdirSync(dirname(path45), { recursive: true });
600
- writeFileSync(path45, MINIMAL_TEMPLATE);
601
- return { path: path45, changed: true, alreadySet: false };
597
+ const path46 = opts.path ?? defaultCmuxConfigPath();
598
+ if (!existsSync(path46)) {
599
+ mkdirSync(dirname(path46), { recursive: true });
600
+ writeFileSync(path46, MINIMAL_TEMPLATE);
601
+ return { path: path46, changed: true, alreadySet: false };
602
602
  }
603
- const text = readFileSync(path45, "utf-8");
603
+ const text = readFileSync(path46, "utf-8");
604
604
  const current = parse(text)?.automation?.socketControlMode;
605
605
  if (current === AUTOMATION_MODE) {
606
- return { path: path45, changed: false, alreadySet: true };
606
+ return { path: path46, changed: false, alreadySet: true };
607
607
  }
608
608
  const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
609
609
  formattingOptions: { insertSpaces: true, tabSize: 2 }
610
610
  });
611
- writeFileSync(path45, applyEdits(text, edits));
612
- return { path: path45, changed: true, alreadySet: false };
611
+ writeFileSync(path46, applyEdits(text, edits));
612
+ return { path: path46, changed: true, alreadySet: false };
613
613
  }
614
614
  var SOCKET_CONTROL_MODE_PATH, AUTOMATION_MODE, MINIMAL_TEMPLATE;
615
615
  var init_cmux_config = __esm({
@@ -762,9 +762,9 @@ import { join as join4 } from "path";
762
762
  function defaultStatePath() {
763
763
  return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
764
764
  }
765
- function readState(path45) {
765
+ function readState(path46) {
766
766
  try {
767
- return JSON.parse(readConfigFileSync(path45));
767
+ return JSON.parse(readConfigFileSync(path46));
768
768
  } catch {
769
769
  return {};
770
770
  }
@@ -925,18 +925,18 @@ function detectDrift(user, def) {
925
925
  }
926
926
  }
927
927
  }
928
- const checkBackend = (path45, backend, agentName) => {
928
+ const checkBackend = (path46, backend, agentName) => {
929
929
  if (backend === void 0)
930
930
  return;
931
931
  if (!isBackendMode(backend)) {
932
- items.push({ path: path45, kind: "invalid", severity: "warn", current: backend, note: "unknown backend; expected native|direct|proxy" });
932
+ items.push({ path: path46, kind: "invalid", severity: "warn", current: backend, note: "unknown backend; expected native|direct|proxy" });
933
933
  return;
934
934
  }
935
935
  if (backend !== "native") {
936
936
  if (agentName !== "claude") {
937
- items.push({ path: path45, kind: "invalid", severity: "warn", current: backend, note: `backend '${backend}' is claude-only (agent '${agentName ?? "?"}')` });
937
+ items.push({ path: path46, kind: "invalid", severity: "warn", current: backend, note: `backend '${backend}' is claude-only (agent '${agentName ?? "?"}')` });
938
938
  } else if (!router) {
939
- items.push({ path: path45, kind: "invalid", severity: "warn", current: backend, note: `backend '${backend}' requires defaults.router` });
939
+ items.push({ path: path46, kind: "invalid", severity: "warn", current: backend, note: `backend '${backend}' requires defaults.router` });
940
940
  }
941
941
  }
942
942
  };
@@ -1124,8 +1124,8 @@ async function notifyIfUpdateAvailable(opts) {
1124
1124
  const statePath2 = opts.statePath ?? UPDATE_CHECK_STATE_PATH;
1125
1125
  const readState2 = opts.readState ?? readUpdateCheckState;
1126
1126
  const writeState = opts.writeState ?? writeUpdateCheckState;
1127
- const write = opts.write ?? ((line) => process.stderr.write(`
1128
- ${line}
1127
+ const write = opts.write ?? ((line2) => process.stderr.write(`
1128
+ ${line2}
1129
1129
  `));
1130
1130
  const outcome = await checkForUpdate({
1131
1131
  currentVersion: opts.currentVersion,
@@ -1480,8 +1480,8 @@ function parseSkill(raw) {
1480
1480
  return null;
1481
1481
  const [, fmBlock, body] = match;
1482
1482
  const fm = {};
1483
- for (const line of fmBlock.split("\n")) {
1484
- const kv = line.match(/^(\w+):\s*(.+)$/);
1483
+ for (const line2 of fmBlock.split("\n")) {
1484
+ const kv = line2.match(/^(\w+):\s*(.+)$/);
1485
1485
  if (kv)
1486
1486
  fm[kv[1]] = kv[2].trim();
1487
1487
  }
@@ -1595,8 +1595,8 @@ async function readDailyLog(workspace, dateStr) {
1595
1595
  const blockerMatch = content.match(/## Blocked\n([\s\S]*?)(?=\n##|$)/);
1596
1596
  if (blockerMatch) {
1597
1597
  const lines = blockerMatch[1].trim().split("\n");
1598
- for (const line of lines) {
1599
- const trimmed = line.replace(/^[-*]\s*/, "").trim();
1598
+ for (const line2 of lines) {
1599
+ const trimmed = line2.replace(/^[-*]\s*/, "").trim();
1600
1600
  if (trimmed && trimmed !== "(none)" && trimmed !== "None") {
1601
1601
  blockers.push(trimmed);
1602
1602
  }
@@ -2702,12 +2702,12 @@ async function* readFromCursor(opts) {
2702
2702
  continue;
2703
2703
  throw e;
2704
2704
  }
2705
- for (const line of buf.split("\n")) {
2706
- if (!line.trim())
2705
+ for (const line2 of buf.split("\n")) {
2706
+ if (!line2.trim())
2707
2707
  continue;
2708
2708
  let entry;
2709
2709
  try {
2710
- entry = JSON.parse(line);
2710
+ entry = JSON.parse(line2);
2711
2711
  } catch {
2712
2712
  continue;
2713
2713
  }
@@ -2809,17 +2809,17 @@ function createDecoder(onParseError) {
2809
2809
  const out = [];
2810
2810
  let idx;
2811
2811
  while ((idx = buf.indexOf("\n")) >= 0) {
2812
- const line = buf.slice(0, idx);
2812
+ const line2 = buf.slice(0, idx);
2813
2813
  buf = buf.slice(idx + 1);
2814
- if (!line.trim())
2814
+ if (!line2.trim())
2815
2815
  continue;
2816
2816
  try {
2817
- const parsed = JSON.parse(line);
2817
+ const parsed = JSON.parse(line2);
2818
2818
  if (typeof parsed === "object" && parsed !== null && parsed.type === "_keepalive")
2819
2819
  continue;
2820
2820
  out.push(parsed);
2821
2821
  } catch {
2822
- onParseError?.(line);
2822
+ onParseError?.(line2);
2823
2823
  }
2824
2824
  }
2825
2825
  return out;
@@ -2979,11 +2979,11 @@ function encodeFrame(f) {
2979
2979
  }
2980
2980
  function decodeFrames(wire) {
2981
2981
  const out = [];
2982
- for (const line of wire.split("\n")) {
2983
- if (!line.trim())
2982
+ for (const line2 of wire.split("\n")) {
2983
+ if (!line2.trim())
2984
2984
  continue;
2985
2985
  try {
2986
- const parsed = JSON.parse(line);
2986
+ const parsed = JSON.parse(line2);
2987
2987
  if (parsed.type === "_keepalive")
2988
2988
  continue;
2989
2989
  out.push(parsed);
@@ -3465,10 +3465,10 @@ function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
3465
3465
  isUpgrade: isVersionUpgrade(parsed.daemonEntry, thisEntry)
3466
3466
  };
3467
3467
  }
3468
- function sanitizePathForPlist(path45) {
3468
+ function sanitizePathForPlist(path46) {
3469
3469
  const seen = /* @__PURE__ */ new Set();
3470
3470
  const stable = [];
3471
- for (const p of path45.split(":")) {
3471
+ for (const p of path46.split(":")) {
3472
3472
  if (!p)
3473
3473
  continue;
3474
3474
  if (p.includes("/.claude/plugins/"))
@@ -4171,14 +4171,14 @@ function detectTrailingQuestion(text) {
4171
4171
  let inFence = false;
4172
4172
  let lastLine = null;
4173
4173
  for (const raw of text.split(/\r?\n/)) {
4174
- const line = raw.trim();
4175
- if (line.startsWith("```")) {
4174
+ const line2 = raw.trim();
4175
+ if (line2.startsWith("```")) {
4176
4176
  inFence = !inFence;
4177
4177
  continue;
4178
4178
  }
4179
- if (inFence || line === "")
4179
+ if (inFence || line2 === "")
4180
4180
  continue;
4181
- lastLine = line;
4181
+ lastLine = line2;
4182
4182
  }
4183
4183
  if (lastLine && lastLine.endsWith("?"))
4184
4184
  return lastLine;
@@ -4189,9 +4189,9 @@ function isQuotedLine(raw) {
4189
4189
  return QUOTED_PREFIX_RE.test(noAnsi);
4190
4190
  }
4191
4191
  function stripChrome(raw) {
4192
- let line = raw.replace(/\[[0-9;]*m/g, "");
4193
- line = line.replace(/^[\s│┃▏▕|]+/, "").replace(/[\s│┃▏▕|]+$/, "");
4194
- const trimmed = line.trim();
4192
+ let line2 = raw.replace(/\[[0-9;]*m/g, "");
4193
+ line2 = line2.replace(/^[\s│┃▏▕|]+/, "").replace(/[\s│┃▏▕|]+$/, "");
4194
+ const trimmed = line2.trim();
4195
4195
  if (trimmed === "")
4196
4196
  return null;
4197
4197
  if (PURE_CHROME_RE.test(trimmed))
@@ -4852,12 +4852,12 @@ function extractUserIntentFromTranscript(jsonl) {
4852
4852
  return null;
4853
4853
  const lines = jsonl.split(/\r?\n/);
4854
4854
  for (let i = lines.length - 1; i >= 0; i--) {
4855
- const line = lines[i].trim();
4856
- if (!line)
4855
+ const line2 = lines[i].trim();
4856
+ if (!line2)
4857
4857
  continue;
4858
4858
  let entry;
4859
4859
  try {
4860
- entry = JSON.parse(line);
4860
+ entry = JSON.parse(line2);
4861
4861
  } catch {
4862
4862
  continue;
4863
4863
  }
@@ -5306,10 +5306,10 @@ async function reapCrewChildren(taskId, graceMs = 2e3, execFn = nodeExec) {
5306
5306
  execFn("ps auxE", { maxBuffer: 64 * 1024 * 1024 }, (err, out) => err ? reject(err) : resolve4(out));
5307
5307
  });
5308
5308
  const pids = [];
5309
- for (const line of stdout.split("\n").slice(1)) {
5310
- if (!line.includes(marker))
5309
+ for (const line2 of stdout.split("\n").slice(1)) {
5310
+ if (!line2.includes(marker))
5311
5311
  continue;
5312
- const pid = parseInt(line.trim().split(/\s+/)[1], 10);
5312
+ const pid = parseInt(line2.trim().split(/\s+/)[1], 10);
5313
5313
  if (!isNaN(pid) && pid !== process.pid)
5314
5314
  pids.push(pid);
5315
5315
  }
@@ -6004,11 +6004,11 @@ var init_captain_record = __esm({
6004
6004
  // packages/core/dist/opencode-session.js
6005
6005
  import { execFileSync as execFileSync4 } from "child_process";
6006
6006
  async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
6007
- for (const path45 of ["/session", "/api/session"]) {
6007
+ for (const path46 of ["/session", "/api/session"]) {
6008
6008
  const ac = new AbortController();
6009
6009
  const t = setTimeout(() => ac.abort(), timeoutMs);
6010
6010
  try {
6011
- const res = await fetchImpl(`http://127.0.0.1:${port}${path45}`, { signal: ac.signal });
6011
+ const res = await fetchImpl(`http://127.0.0.1:${port}${path46}`, { signal: ac.signal });
6012
6012
  if (!res.ok)
6013
6013
  continue;
6014
6014
  const rows = await res.json();
@@ -6023,8 +6023,8 @@ async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
6023
6023
  }
6024
6024
  function parseLiveOpencodeServers(psOutput) {
6025
6025
  const out = [];
6026
- for (const line of psOutput.split("\n")) {
6027
- const m = line.match(/^\s*(\d+)\s+(.+)$/);
6026
+ for (const line2 of psOutput.split("\n")) {
6027
+ const m = line2.match(/^\s*(\d+)\s+(.+)$/);
6028
6028
  if (!m)
6029
6029
  continue;
6030
6030
  const pid = Number(m[1]);
@@ -6050,8 +6050,8 @@ function defaultPsOutput() {
6050
6050
  function defaultCwdOf(pid) {
6051
6051
  try {
6052
6052
  const out = execFileSync4("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], { encoding: "utf-8", timeout: 2e3 });
6053
- const line = out.split("\n").find((l) => l.startsWith("n"));
6054
- return line ? line.slice(1) : null;
6053
+ const line2 = out.split("\n").find((l) => l.startsWith("n"));
6054
+ return line2 ? line2.slice(1) : null;
6055
6055
  } catch {
6056
6056
  return null;
6057
6057
  }
@@ -6701,10 +6701,10 @@ function distBuiltAt() {
6701
6701
  return 0;
6702
6702
  }
6703
6703
  }
6704
- function gatherLogStats(path45, now, windowMs) {
6704
+ function gatherLogStats(path46, now, windowMs) {
6705
6705
  let sizeBytes = 0;
6706
6706
  try {
6707
- sizeBytes = statSync3(path45).size;
6707
+ sizeBytes = statSync3(path46).size;
6708
6708
  } catch {
6709
6709
  return { errorCount: 0, sizeBytes: 0, windowMs };
6710
6710
  }
@@ -6715,7 +6715,7 @@ function gatherLogStats(path45, now, windowMs) {
6715
6715
  const len = sizeBytes - start;
6716
6716
  let text = "";
6717
6717
  try {
6718
- const fd = openSync2(path45, "r");
6718
+ const fd = openSync2(path46, "r");
6719
6719
  try {
6720
6720
  const buf = Buffer.alloc(len);
6721
6721
  readSync(fd, buf, 0, len, start);
@@ -6728,10 +6728,10 @@ function gatherLogStats(path45, now, windowMs) {
6728
6728
  }
6729
6729
  const cutoff = now - windowMs;
6730
6730
  let errorCount = 0;
6731
- for (const line of text.split("\n")) {
6732
- if (!/error|failed/i.test(line))
6731
+ for (const line2 of text.split("\n")) {
6732
+ if (!/error|failed/i.test(line2))
6733
6733
  continue;
6734
- const m = line.match(/\d{4}-\d{2}-\d{2}T[\d:.]+Z/);
6734
+ const m = line2.match(/\d{4}-\d{2}-\d{2}T[\d:.]+Z/);
6735
6735
  if (m) {
6736
6736
  const ts = Date.parse(m[0]);
6737
6737
  if (!Number.isNaN(ts) && ts < cutoff)
@@ -8906,10 +8906,10 @@ function scan(bufRef, acc) {
8906
8906
  let saw = false;
8907
8907
  let idx;
8908
8908
  while ((idx = bufRef.value.indexOf("\n")) !== -1) {
8909
- const line = bufRef.value.slice(0, idx).trim();
8909
+ const line2 = bufRef.value.slice(0, idx).trim();
8910
8910
  bufRef.value = bufRef.value.slice(idx + 1);
8911
- if (line.startsWith("data:")) {
8912
- const payload = line.slice(5).trim();
8911
+ if (line2.startsWith("data:")) {
8912
+ const payload = line2.slice(5).trim();
8913
8913
  if (payload && payload !== "[DONE]") {
8914
8914
  try {
8915
8915
  if (absorb(JSON.parse(payload), acc))
@@ -8960,8 +8960,8 @@ var init_stream = __esm({
8960
8960
  // packages/core/dist/router/shim.js
8961
8961
  import { createServer as createServer3 } from "http";
8962
8962
  import { Readable } from "stream";
8963
- function joinUrl(base, path45) {
8964
- return base.replace(/\/+$/, "") + path45;
8963
+ function joinUrl(base, path46) {
8964
+ return base.replace(/\/+$/, "") + path46;
8965
8965
  }
8966
8966
  async function readBody(req) {
8967
8967
  const chunks = [];
@@ -9137,8 +9137,8 @@ function createRouterShim(opts) {
9137
9137
  writeJson(res, 200, { input_tokens: Math.max(1, Math.ceil(text.length / 4)) });
9138
9138
  }
9139
9139
  function handler(req, res) {
9140
- const path45 = pathnameOf(req.url);
9141
- if (req.method === "POST" && path45 === "/v1/messages") {
9140
+ const path46 = pathnameOf(req.url);
9141
+ if (req.method === "POST" && path46 === "/v1/messages") {
9142
9142
  void handleMessages(req, res).catch((err) => {
9143
9143
  log(`router internal error: ${err instanceof Error ? err.message : String(err)}`);
9144
9144
  if (!res.headersSent) {
@@ -9150,18 +9150,18 @@ function createRouterShim(opts) {
9150
9150
  });
9151
9151
  return;
9152
9152
  }
9153
- if (req.method === "POST" && path45 === "/v1/messages/count_tokens") {
9153
+ if (req.method === "POST" && path46 === "/v1/messages/count_tokens") {
9154
9154
  void handleCountTokens(req, res).catch(() => {
9155
9155
  if (!res.headersSent)
9156
9156
  writeJson(res, 502, anthropicError(502, "api_error", "router internal error").body);
9157
9157
  });
9158
9158
  return;
9159
9159
  }
9160
- if (req.method === "GET" && path45 === "/v1/models") {
9160
+ if (req.method === "GET" && path46 === "/v1/models") {
9161
9161
  writeJson(res, 200, modelsList([...advertisedModels]));
9162
9162
  return;
9163
9163
  }
9164
- if (req.method === "GET" && path45 === "/healthz") {
9164
+ if (req.method === "GET" && path46 === "/healthz") {
9165
9165
  writeJson(res, 200, { ready: server?.listening === true, upstreamReachable, lastError });
9166
9166
  return;
9167
9167
  }
@@ -9430,11 +9430,11 @@ async function probeCaptainChannel(project, opts = {}) {
9430
9430
  }
9431
9431
  }
9432
9432
  async function httpReachable(port, fetchImpl, timeoutMs) {
9433
- for (const path45 of ["/session", "/api/session"]) {
9433
+ for (const path46 of ["/session", "/api/session"]) {
9434
9434
  const ac = new AbortController();
9435
9435
  const t = setTimeout(() => ac.abort(), timeoutMs);
9436
9436
  try {
9437
- const res = await fetchImpl(`http://127.0.0.1:${port}${path45}`, { signal: ac.signal });
9437
+ const res = await fetchImpl(`http://127.0.0.1:${port}${path46}`, { signal: ac.signal });
9438
9438
  if (res.ok)
9439
9439
  return true;
9440
9440
  } catch {
@@ -10216,8 +10216,12 @@ var init_paths = __esm({
10216
10216
 
10217
10217
  // packages/core/dist/knowledge/store.js
10218
10218
  import fs15 from "fs";
10219
+ import os7 from "os";
10219
10220
  import path15 from "path";
10220
10221
  import matter2 from "gray-matter";
10222
+ function duplicateIdProblem(id, ignored, used) {
10223
+ 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.`;
10224
+ }
10221
10225
  function splitStatement(body) {
10222
10226
  const first = body.trim().split(/\n\s*\n/)[0] ?? "";
10223
10227
  return first.replace(/\s+/g, " ").trim();
@@ -10262,7 +10266,7 @@ function loadRulesDir(dir, layer, opts = {}) {
10262
10266
  const fm = parsed.data;
10263
10267
  const prior = seen.get(fm.id);
10264
10268
  if (prior) {
10265
- errors.push({ file, problems: [`duplicate id ${fm.id} (also in ${prior})`] });
10269
+ errors.push({ file, problems: [duplicateIdProblem(fm.id, file, prior)] });
10266
10270
  continue;
10267
10271
  }
10268
10272
  seen.set(fm.id, file);
@@ -10270,7 +10274,65 @@ function loadRulesDir(dir, layer, opts = {}) {
10270
10274
  }
10271
10275
  return { rules, errors };
10272
10276
  }
10273
- var NO_JS_FRONTMATTER;
10277
+ function resolveSourceRef(ref, kbRoot, sources) {
10278
+ const bases = /* @__PURE__ */ new Set([kbRoot]);
10279
+ for (const s of sources) {
10280
+ let d = path15.resolve(kbRoot, expandHome(s.path.split(/[*?[{]/)[0]));
10281
+ for (let i = 0; i < 6 && d !== path15.dirname(d); i++) {
10282
+ d = path15.dirname(d);
10283
+ bases.add(d);
10284
+ }
10285
+ }
10286
+ const cands = [path15.resolve(kbRoot, expandHome(ref)), ...[...bases].map((b) => path15.join(b, ref))];
10287
+ return cands.find((c) => fs15.existsSync(c) && fs15.statSync(c).isFile());
10288
+ }
10289
+ function validateKb(opts) {
10290
+ const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
10291
+ const checks = [];
10292
+ const dups = errors.filter((e) => e.problems.some((p) => p.startsWith("duplicate id")));
10293
+ const invalid = errors.filter((e) => !dups.includes(e));
10294
+ const proposed = rules.filter((r) => path15.relative(opts.rulesDir, r.file).split(path15.sep).includes(PROPOSED_DIR)).length;
10295
+ checks.push({ level: "ok", message: `${rules.length + errors.length} rule files read (${rules.length - proposed} live, ${proposed} proposed parsed OK)` });
10296
+ if (invalid.length)
10297
+ for (const e of invalid)
10298
+ checks.push({ level: "fail", message: `invalid ${e.file}: ${e.problems.join("; ")}` });
10299
+ else
10300
+ checks.push({ level: "ok", message: "no invalid rule files" });
10301
+ if (dups.length)
10302
+ for (const e of dups)
10303
+ checks.push({ level: "fail", message: e.problems.join("; ") });
10304
+ else
10305
+ checks.push({ level: "ok", message: "no duplicate ids" });
10306
+ const cache = /* @__PURE__ */ new Map();
10307
+ let verified = 0, unresolved = 0;
10308
+ for (const r of rules) {
10309
+ r.sources.forEach((src, i) => {
10310
+ const file = resolveSourceRef(src.ref, opts.kbRoot, opts.sources);
10311
+ if (!file) {
10312
+ unresolved++;
10313
+ return;
10314
+ }
10315
+ if (!cache.has(file))
10316
+ cache.set(file, fs15.readFileSync(file, "utf8"));
10317
+ if (cache.get(file).includes(src.quote))
10318
+ verified++;
10319
+ else
10320
+ checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
10321
+ });
10322
+ }
10323
+ if (!checks.some((c) => c.message.startsWith("quote not found")))
10324
+ checks.push({ level: "ok", message: `${verified} source quotes found in their source files` });
10325
+ if (unresolved)
10326
+ checks.push({ level: "skip", message: `${unresolved} source refs not resolvable on this machine, quote not checked` });
10327
+ if (opts.domains) {
10328
+ for (const r of rules) {
10329
+ if (!opts.domains.includes(r.domain))
10330
+ checks.push({ level: "warn", message: `${r.id}: domain '${r.domain}' not in allowed domains [${opts.domains.join(", ")}] (${r.file})` });
10331
+ }
10332
+ }
10333
+ return { checks, ok: !checks.some((c) => c.level === "fail") };
10334
+ }
10335
+ var NO_JS_FRONTMATTER, expandHome;
10274
10336
  var init_store2 = __esm({
10275
10337
  "packages/core/dist/knowledge/store.js"() {
10276
10338
  init_dist();
@@ -10280,6 +10342,7 @@ var init_store2 = __esm({
10280
10342
  throw new Error("only YAML front matter is allowed");
10281
10343
  } } }
10282
10344
  };
10345
+ expandHome = (p) => p === "~" || p.startsWith("~/") ? path15.join(os7.homedir(), p.slice(1)) : p;
10283
10346
  }
10284
10347
  });
10285
10348
 
@@ -10368,7 +10431,7 @@ var init_index_file = __esm({
10368
10431
 
10369
10432
  // packages/core/dist/knowledge/search.js
10370
10433
  function searchRules(rules, query, opts = {}) {
10371
- const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
10434
+ const terms = [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))];
10372
10435
  if (terms.length === 0)
10373
10436
  return [];
10374
10437
  const statuses = opts.statuses ?? DEFAULT_SEARCH_STATUSES;
@@ -10380,30 +10443,45 @@ function searchRules(rules, query, opts = {}) {
10380
10443
  const expanded = lower(rule2.triggers?.expanded);
10381
10444
  const when = (rule2.triggers?.when ?? "").toLowerCase();
10382
10445
  const statement = rule2.statement.toLowerCase();
10446
+ const rationale = rationaleOf(rule2);
10383
10447
  const id = rule2.id.toLowerCase();
10384
10448
  let score = 0;
10449
+ let matched = 0;
10450
+ let curated = false;
10385
10451
  for (const t of terms) {
10452
+ let s = 0;
10386
10453
  if (id.includes(t))
10387
- score += 3;
10454
+ s += 3;
10455
+ if (keywords.includes(t) || expanded.includes(t))
10456
+ curated = true;
10388
10457
  if (keywords.includes(t))
10389
- score += 3;
10458
+ s += 3;
10390
10459
  if (expanded.includes(t))
10391
- score += 2;
10460
+ s += 3;
10392
10461
  if (when.includes(t))
10393
- score += 2;
10462
+ s += 2;
10394
10463
  if (statement.includes(t))
10395
- score += 1;
10464
+ s += 2;
10465
+ if (rationale.includes(t))
10466
+ s += 1;
10467
+ if (s > 0) {
10468
+ matched++;
10469
+ score += s;
10470
+ }
10396
10471
  }
10397
10472
  if (score > 0)
10398
- hits.push({ rule: rule2, score });
10473
+ hits.push({ rule: rule2, score, matched, curated });
10399
10474
  }
10400
- return hits.sort((a, b) => b.score - a.score || a.rule.id.localeCompare(b.rule.id));
10475
+ const strong = terms.length >= 2 ? hits.filter((h) => h.matched >= 2 || h.curated) : hits;
10476
+ const out = strong.length ? strong : hits;
10477
+ return out.sort((a, b) => b.score - a.score || a.rule.id.localeCompare(b.rule.id));
10401
10478
  }
10402
- var DEFAULT_SEARCH_STATUSES, lower;
10479
+ var DEFAULT_SEARCH_STATUSES, lower, rationaleOf;
10403
10480
  var init_search = __esm({
10404
10481
  "packages/core/dist/knowledge/search.js"() {
10405
10482
  DEFAULT_SEARCH_STATUSES = ["active", "stale"];
10406
10483
  lower = (xs) => (xs ?? []).map((x) => x.toLowerCase());
10484
+ rationaleOf = (rule2) => rule2.body.slice(rule2.statement.length).toLowerCase();
10407
10485
  }
10408
10486
  });
10409
10487
 
@@ -10539,28 +10617,28 @@ function requireSnippet() {
10539
10617
  const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3);
10540
10618
  for (let i = 1; i <= options.linesBefore; i++) {
10541
10619
  if (foundLineNo - i < 0) break;
10542
- const line2 = getLine(
10620
+ const line22 = getLine(
10543
10621
  mark2.buffer,
10544
10622
  lineStarts[foundLineNo - i],
10545
10623
  lineEnds[foundLineNo - i],
10546
10624
  mark2.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]),
10547
10625
  maxLineLength
10548
10626
  );
10549
- result = common2.repeat(" ", options.indent) + padStart((mark2.line - i + 1).toString(), lineNoLength) + " | " + line2.str + "\n" + result;
10627
+ result = common2.repeat(" ", options.indent) + padStart((mark2.line - i + 1).toString(), lineNoLength) + " | " + line22.str + "\n" + result;
10550
10628
  }
10551
- const line = getLine(mark2.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark2.position, maxLineLength);
10552
- result += common2.repeat(" ", options.indent) + padStart((mark2.line + 1).toString(), lineNoLength) + " | " + line.str + "\n";
10553
- result += common2.repeat("-", options.indent + lineNoLength + 3 + line.pos) + "^\n";
10629
+ const line2 = getLine(mark2.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark2.position, maxLineLength);
10630
+ result += common2.repeat(" ", options.indent) + padStart((mark2.line + 1).toString(), lineNoLength) + " | " + line2.str + "\n";
10631
+ result += common2.repeat("-", options.indent + lineNoLength + 3 + line2.pos) + "^\n";
10554
10632
  for (let i = 1; i <= options.linesAfter; i++) {
10555
10633
  if (foundLineNo + i >= lineEnds.length) break;
10556
- const line2 = getLine(
10634
+ const line22 = getLine(
10557
10635
  mark2.buffer,
10558
10636
  lineStarts[foundLineNo + i],
10559
10637
  lineEnds[foundLineNo + i],
10560
10638
  mark2.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]),
10561
10639
  maxLineLength
10562
10640
  );
10563
- result += common2.repeat(" ", options.indent) + padStart((mark2.line + i + 1).toString(), lineNoLength) + " | " + line2.str + "\n";
10641
+ result += common2.repeat(" ", options.indent) + padStart((mark2.line + i + 1).toString(), lineNoLength) + " | " + line22.str + "\n";
10564
10642
  }
10565
10643
  return result.replace(/\n$/, "");
10566
10644
  }
@@ -12847,17 +12925,17 @@ function requireDumper() {
12847
12925
  let result = "";
12848
12926
  const length = string.length;
12849
12927
  while (position < length) {
12850
- let line;
12928
+ let line2;
12851
12929
  const next = string.indexOf("\n", position);
12852
12930
  if (next === -1) {
12853
- line = string.slice(position);
12931
+ line2 = string.slice(position);
12854
12932
  position = length;
12855
12933
  } else {
12856
- line = string.slice(position, next + 1);
12934
+ line2 = string.slice(position, next + 1);
12857
12935
  position = next + 1;
12858
12936
  }
12859
- if (line.length && line !== "\n") result += ind;
12860
- result += line;
12937
+ if (line2.length && line2 !== "\n") result += ind;
12938
+ result += line2;
12861
12939
  }
12862
12940
  return result;
12863
12941
  }
@@ -13042,15 +13120,15 @@ function requireDumper() {
13042
13120
  let match;
13043
13121
  while (match = lineRe.exec(string)) {
13044
13122
  const prefix = match[1];
13045
- const line = match[2];
13046
- moreIndented = line[0] === " ";
13047
- result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width);
13123
+ const line2 = match[2];
13124
+ moreIndented = line2[0] === " ";
13125
+ result += prefix + (!prevMoreIndented && !moreIndented && line2 !== "" ? "\n" : "") + foldLine(line2, width);
13048
13126
  prevMoreIndented = moreIndented;
13049
13127
  }
13050
13128
  return result;
13051
13129
  }
13052
- function foldLine(line, width) {
13053
- if (line === "" || line[0] === " ") return line;
13130
+ function foldLine(line2, width) {
13131
+ if (line2 === "" || line2[0] === " ") return line2;
13054
13132
  const breakRe = / [^ ]/g;
13055
13133
  let match;
13056
13134
  let start = 0;
@@ -13058,20 +13136,20 @@ function requireDumper() {
13058
13136
  let curr = 0;
13059
13137
  let next = 0;
13060
13138
  let result = "";
13061
- while (match = breakRe.exec(line)) {
13139
+ while (match = breakRe.exec(line2)) {
13062
13140
  next = match.index;
13063
13141
  if (next - start > width) {
13064
13142
  end = curr > start ? curr : next;
13065
- result += "\n" + line.slice(start, end);
13143
+ result += "\n" + line2.slice(start, end);
13066
13144
  start = end + 1;
13067
13145
  }
13068
13146
  curr = next;
13069
13147
  }
13070
13148
  result += "\n";
13071
- if (line.length - start > width && curr > start) {
13072
- result += line.slice(start, curr) + "\n" + line.slice(curr + 1);
13149
+ if (line2.length - start > width && curr > start) {
13150
+ result += line2.slice(start, curr) + "\n" + line2.slice(curr + 1);
13073
13151
  } else {
13074
- result += line.slice(start);
13152
+ result += line2.slice(start);
13075
13153
  }
13076
13154
  return result.slice(1);
13077
13155
  }
@@ -13480,6 +13558,220 @@ var init_sources = __esm({
13480
13558
  }
13481
13559
  });
13482
13560
 
13561
+ // packages/core/dist/knowledge/inject.js
13562
+ import fs19 from "fs";
13563
+ import path18 from "path";
13564
+ function sessionOrder(a, b) {
13565
+ const proj = (r) => r.layer.startsWith("project:") ? 0 : 1;
13566
+ const mod = (r) => r.modality === "must-not" ? 0 : 1;
13567
+ return proj(a) - proj(b) || mod(a) - mod(b) || a.id.localeCompare(b.id);
13568
+ }
13569
+ function formatSessionContext(kbs, rules, cap = SESSION_RULE_CAP) {
13570
+ const hard = rules.filter((r) => r.status === "active" && (r.modality === "must" || r.modality === "must-not")).sort(sessionOrder);
13571
+ const shown = hard.slice(0, cap);
13572
+ const lines = [
13573
+ `<squadrant-project-rules kb="${kbs.join(",")}">`,
13574
+ `Rules KB: ${kbs.join(", ")}. ${DATA_NOTE}`,
13575
+ ...shown.map(line)
13576
+ ];
13577
+ if (hard.length > shown.length)
13578
+ lines.push(`+${hard.length - shown.length} more: squadrant rules list --brief`);
13579
+ lines.push("Look up rules for a task with `squadrant rules search <terms>` / `squadrant rules show <id>` (rules-ops skill).");
13580
+ lines.push("</squadrant-project-rules>");
13581
+ return { text: lines.join("\n"), ids: shown.map((r) => r.id) };
13582
+ }
13583
+ function cleanPromptQuery(prompt) {
13584
+ const text = prompt.replace(/```[\s\S]*?(```|$)/g, " ").split("\n").filter((l) => l.length <= MAX_LINE_CHARS).join("\n").slice(0, MAX_PROMPT_CHARS).toLowerCase().replace(/https?:\/\/\S+/g, " ");
13585
+ const terms = [];
13586
+ const add = (t) => {
13587
+ if (t.length < 3 && !SHORT_TERMS.has(t) || /^\d+$/.test(t) || STOPWORDS.has(t) || terms.includes(t))
13588
+ return;
13589
+ terms.push(t);
13590
+ };
13591
+ for (const raw of text.split(/[^a-z0-9._-]+/)) {
13592
+ const t = raw.replace(/^[._-]+|[._-]+$/g, "");
13593
+ if (STOPWORDS.has(t))
13594
+ continue;
13595
+ add(t);
13596
+ const parts = t.split(/[._-]+/);
13597
+ if (parts.length > 1 && parts.every((x) => x.length >= 3 && !PREFIXES.has(x)))
13598
+ parts.forEach(add);
13599
+ if (terms.length >= MAX_TERMS)
13600
+ break;
13601
+ }
13602
+ return terms.slice(0, MAX_TERMS).join(" ");
13603
+ }
13604
+ function wholeWordTerms(rule2, terms) {
13605
+ const text = [
13606
+ rule2.id,
13607
+ ...rule2.triggers?.keywords ?? [],
13608
+ ...rule2.triggers?.expanded ?? [],
13609
+ rule2.triggers?.when ?? "",
13610
+ rule2.statement
13611
+ ].join("\n").toLowerCase();
13612
+ return terms.filter((t) => {
13613
+ const base = t.length > 4 ? t.replace(/(es|s)$/, "") : t;
13614
+ return new RegExp(`(^|[^a-z0-9])(?:${escapeRe(t)}|${escapeRe(base)}(?:s|es)?)($|[^a-z0-9])`).test(text);
13615
+ });
13616
+ }
13617
+ function selectPromptHits(hits, query, seen, opts = {}) {
13618
+ const minScore = opts.minScore ?? PROMPT_MIN_SCORE;
13619
+ const terms = query.split(" ").filter(Boolean);
13620
+ return hits.filter((h) => {
13621
+ if (seen.has(h.rule.id))
13622
+ return false;
13623
+ const n = wholeWordTerms(h.rule, terms).length;
13624
+ return n >= 2 && h.score >= minScore || n === 1 && h.score >= PROMPT_SINGLE_TERM_MIN_SCORE;
13625
+ }).slice(0, opts.cap ?? PROMPT_RULE_CAP);
13626
+ }
13627
+ function isSystemPrompt(prompt) {
13628
+ const t = prompt.trimStart();
13629
+ return /^(⚠|🗒|\[stale\b|CREW [A-Z]|Another Claude session sent a message)/u.test(t) || t.includes("<cross-session-message");
13630
+ }
13631
+ function promptText(prompt) {
13632
+ const m = BRIEF_POINTER_RE.exec(prompt.trimStart());
13633
+ if (!m)
13634
+ return prompt;
13635
+ try {
13636
+ return fs19.readFileSync(m[1], "utf8").slice(0, MAX_PROMPT_CHARS * 2);
13637
+ } catch {
13638
+ return prompt;
13639
+ }
13640
+ }
13641
+ function formatPromptContext(hits) {
13642
+ return [
13643
+ '<squadrant-project-rules match="prompt">',
13644
+ `Rules that may apply to this prompt. ${DATA_NOTE}`,
13645
+ ...hits.map((h) => line(h.rule)),
13646
+ "</squadrant-project-rules>"
13647
+ ].join("\n");
13648
+ }
13649
+ function injectStateDir(stateRoot) {
13650
+ return path18.join(stateRoot, "rules-inject");
13651
+ }
13652
+ function readSeenRules(stateRoot, sessionId) {
13653
+ try {
13654
+ const ids = JSON.parse(fs19.readFileSync(sessionFile(stateRoot, sessionId), "utf8"));
13655
+ return new Set(Array.isArray(ids) ? ids.filter((x) => typeof x === "string") : []);
13656
+ } catch {
13657
+ return /* @__PURE__ */ new Set();
13658
+ }
13659
+ }
13660
+ function recordSeenRules(stateRoot, sessionId, ids) {
13661
+ if (!ids.length)
13662
+ return;
13663
+ const seen = readSeenRules(stateRoot, sessionId);
13664
+ for (const id of ids)
13665
+ seen.add(id);
13666
+ fs19.mkdirSync(injectStateDir(stateRoot), { recursive: true });
13667
+ fs19.writeFileSync(sessionFile(stateRoot, sessionId), JSON.stringify([...seen]));
13668
+ }
13669
+ function pruneSeenRules(stateRoot, now = Date.now()) {
13670
+ const dir = injectStateDir(stateRoot);
13671
+ let names;
13672
+ try {
13673
+ names = fs19.readdirSync(dir);
13674
+ } catch {
13675
+ return;
13676
+ }
13677
+ for (const n of names) {
13678
+ const f = path18.join(dir, n);
13679
+ try {
13680
+ if (now - fs19.statSync(f).mtimeMs > SEEN_TTL_MS)
13681
+ fs19.unlinkSync(f);
13682
+ } catch {
13683
+ }
13684
+ }
13685
+ }
13686
+ async function withBudget(fn, budgetMs = INJECT_BUDGET_MS) {
13687
+ const start = Date.now();
13688
+ let timer;
13689
+ try {
13690
+ const timeout = new Promise((resolve4) => {
13691
+ timer = setTimeout(() => resolve4(null), budgetMs);
13692
+ });
13693
+ const out = await Promise.race([Promise.resolve().then(fn), timeout]);
13694
+ return Date.now() - start > budgetMs ? null : out;
13695
+ } catch {
13696
+ return null;
13697
+ } finally {
13698
+ clearTimeout(timer);
13699
+ }
13700
+ }
13701
+ function resolveInjectProject(cfg, cwd, env, project) {
13702
+ const named = project ?? env.SQUADRANT_CREW_PROJECT;
13703
+ if (named)
13704
+ return cfg.projects[named] ? named : null;
13705
+ let best = null;
13706
+ let bestLen = -1;
13707
+ for (const [name, pc] of Object.entries(cfg.projects)) {
13708
+ const root = resolveHome(pc.path);
13709
+ if ((cwd === root || cwd.startsWith(root + path18.sep)) && root.length > bestLen) {
13710
+ best = name;
13711
+ bestLen = root.length;
13712
+ }
13713
+ }
13714
+ return best;
13715
+ }
13716
+ function computeRulesInjection(i) {
13717
+ if (i.env.SQUADRANT_RULES_INJECT === "0")
13718
+ return null;
13719
+ const p = typeof i.payload === "object" && i.payload !== null ? i.payload : {};
13720
+ const cwd = typeof p.cwd === "string" && p.cwd ? p.cwd : i.cwd;
13721
+ const project = resolveInjectProject(i.cfg, cwd, i.env, i.project);
13722
+ if (!project)
13723
+ return null;
13724
+ const kbs = subscribedKbs(i.cfg, project);
13725
+ if (!kbs.length)
13726
+ return null;
13727
+ const sessionId = typeof p.session_id === "string" && p.session_id ? p.session_id : null;
13728
+ if (i.event === "session-start") {
13729
+ const { text, ids } = formatSessionContext(kbs, resolveProjectRules(i.cfg, project).rules);
13730
+ if (sessionId) {
13731
+ pruneSeenRules(i.stateRoot);
13732
+ recordSeenRules(i.stateRoot, sessionId, ids);
13733
+ }
13734
+ return text;
13735
+ }
13736
+ if (typeof p.prompt !== "string" || isSystemPrompt(p.prompt))
13737
+ return null;
13738
+ const query = cleanPromptQuery(promptText(p.prompt));
13739
+ if (!query)
13740
+ return null;
13741
+ const seen = sessionId ? readSeenRules(i.stateRoot, sessionId) : /* @__PURE__ */ new Set();
13742
+ const picked = selectPromptHits(searchRules(resolveProjectRules(i.cfg, project).rules, query), query, seen);
13743
+ if (!picked.length)
13744
+ return null;
13745
+ if (sessionId)
13746
+ recordSeenRules(i.stateRoot, sessionId, picked.map((h) => h.rule.id));
13747
+ return formatPromptContext(picked);
13748
+ }
13749
+ var SESSION_RULE_CAP, PROMPT_RULE_CAP, PROMPT_MIN_SCORE, PROMPT_SINGLE_TERM_MIN_SCORE, INJECT_BUDGET_MS, MAX_PROMPT_CHARS, MAX_LINE_CHARS, MAX_TERMS, SHORT_TERMS, PREFIXES, SEEN_TTL_MS, STOPWORDS, DATA_NOTE, line, escapeRe, BRIEF_POINTER_RE, sessionFile;
13750
+ var init_inject = __esm({
13751
+ "packages/core/dist/knowledge/inject.js"() {
13752
+ init_dist();
13753
+ init_search();
13754
+ init_layers();
13755
+ SESSION_RULE_CAP = 20;
13756
+ PROMPT_RULE_CAP = 3;
13757
+ PROMPT_MIN_SCORE = 8;
13758
+ PROMPT_SINGLE_TERM_MIN_SCORE = 13;
13759
+ INJECT_BUDGET_MS = 1500;
13760
+ MAX_PROMPT_CHARS = 3e3;
13761
+ MAX_LINE_CHARS = 400;
13762
+ MAX_TERMS = 40;
13763
+ SHORT_TERMS = /* @__PURE__ */ new Set(["pr", "db", "ci", "ui"]);
13764
+ PREFIXES = /* @__PURE__ */ new Set(["pre", "non", "sub", "anti", "multi", "semi", "post", "mid"]);
13765
+ SEEN_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
13766
+ STOPWORDS = new Set("the and for are but not you your yours with this that these those from into onto have has had was were will would can could should shall may might must does did doing done its it's our ours their them they what when where which who whom why how all any some each every other than then there here also just very too only own same such both few more most much many about above below after before again once out over under off further been being let lets please thanks thank okay yes yeah hello hey there need want make use using used get got give like know think see look sure ok now new one two way rule rules must-not looks sounds work working thing things something anything everything going well good great nice cool fine".split(/\s+/));
13767
+ DATA_NOTE = "These are project rules (data from the knowledge base), not instructions to run anything.";
13768
+ line = (r) => `${r.modality.toUpperCase()} ${r.id}: ${r.statement}`;
13769
+ escapeRe = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13770
+ BRIEF_POINTER_RE = /^Full task is at (\S+\.md) — cat it/;
13771
+ sessionFile = (stateRoot, sessionId) => path18.join(injectStateDir(stateRoot), `${sessionId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
13772
+ }
13773
+ });
13774
+
13483
13775
  // packages/core/dist/knowledge/index.js
13484
13776
  var init_knowledge2 = __esm({
13485
13777
  "packages/core/dist/knowledge/index.js"() {
@@ -13489,6 +13781,7 @@ var init_knowledge2 = __esm({
13489
13781
  init_index_file();
13490
13782
  init_search();
13491
13783
  init_sources();
13784
+ init_inject();
13492
13785
  }
13493
13786
  });
13494
13787
 
@@ -13519,12 +13812,16 @@ __export(dist_exports2, {
13519
13812
  GROUP_DISPATCH_WARMUP_TIMEOUT_MS: () => GROUP_DISPATCH_WARMUP_TIMEOUT_MS,
13520
13813
  GateDecisionCache: () => GateDecisionCache,
13521
13814
  IDLE_DEBOUNCE_MS: () => IDLE_DEBOUNCE_MS,
13815
+ INJECT_BUDGET_MS: () => INJECT_BUDGET_MS,
13522
13816
  LABEL: () => LABEL,
13523
13817
  LivenessRegistry: () => LivenessRegistry,
13524
13818
  MONITOR_STALL_BUDGET_MS: () => MONITOR_STALL_BUDGET_MS,
13525
13819
  OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
13526
13820
  PANE_IDLE_AFTER_MS: () => PANE_IDLE_AFTER_MS,
13527
13821
  PROBE_QUIET_MS: () => PROBE_QUIET_MS,
13822
+ PROMPT_MIN_SCORE: () => PROMPT_MIN_SCORE,
13823
+ PROMPT_RULE_CAP: () => PROMPT_RULE_CAP,
13824
+ PROMPT_SINGLE_TERM_MIN_SCORE: () => PROMPT_SINGLE_TERM_MIN_SCORE,
13528
13825
  PROPOSED_DIR: () => PROPOSED_DIR,
13529
13826
  PROTOCOL_VERSION: () => PROTOCOL_VERSION,
13530
13827
  READ_ONLY_CREW_SUBCOMMANDS: () => READ_ONLY_CREW_SUBCOMMANDS,
@@ -13532,6 +13829,7 @@ __export(dist_exports2, {
13532
13829
  ROUTER_READY_ATTEMPTS: () => ROUTER_READY_ATTEMPTS,
13533
13830
  ROUTER_READY_DELAY_MS: () => ROUTER_READY_DELAY_MS,
13534
13831
  SERVER_TOOL_TYPE_RE: () => SERVER_TOOL_TYPE_RE,
13832
+ SESSION_RULE_CAP: () => SESSION_RULE_CAP,
13535
13833
  SIDE_SESSION_ENV: () => SIDE_SESSION_ENV,
13536
13834
  SOURCES_TEMPLATE: () => SOURCES_TEMPLATE,
13537
13835
  STALE_THRESHOLD_MS: () => STALE_THRESHOLD_MS,
@@ -13572,9 +13870,11 @@ __export(dist_exports2, {
13572
13870
  classifyCaptainPane: () => classifyCaptainPane,
13573
13871
  classifyHealth: () => classifyHealth,
13574
13872
  claudeEnvShadowsRouter: () => claudeEnvShadowsRouter,
13873
+ cleanPromptQuery: () => cleanPromptQuery,
13575
13874
  clearPending: () => clearPending,
13576
13875
  closeWorkItem: () => closeWorkItem,
13577
13876
  compileIndex: () => compileIndex,
13877
+ computeRulesInjection: () => computeRulesInjection,
13578
13878
  computeTemplateHash: () => computeTemplateHash,
13579
13879
  consumeExitMarker: () => consumeExitMarker,
13580
13880
  createAttach: () => createAttach,
@@ -13626,6 +13926,7 @@ __export(dist_exports2, {
13626
13926
  discoverCaptainSurface: () => discoverCaptainSurface,
13627
13927
  discoverLiveOpencodeServer: () => discoverLiveOpencodeServer,
13628
13928
  dispatchToSibling: () => dispatchToSibling,
13929
+ duplicateIdProblem: () => duplicateIdProblem,
13629
13930
  encodeFrame: () => encodeFrame,
13630
13931
  encodeMsg: () => encodeMsg,
13631
13932
  ensureDaemon: () => ensureDaemon,
@@ -13647,6 +13948,8 @@ __export(dist_exports2, {
13647
13948
  formatLifecycle: () => formatLifecycle,
13648
13949
  formatMediaReceipt: () => formatMediaReceipt,
13649
13950
  formatPermissionDecision: () => formatPermissionDecision,
13951
+ formatPromptContext: () => formatPromptContext,
13952
+ formatSessionContext: () => formatSessionContext,
13650
13953
  formatUsageLine: () => formatUsageLine,
13651
13954
  formatWatchdogWarning: () => formatWatchdogWarning,
13652
13955
  freshTrace: () => freshTrace,
@@ -13656,6 +13959,7 @@ __export(dist_exports2, {
13656
13959
  hasModalOptionList: () => hasModalOptionList,
13657
13960
  healCmdFor: () => healCmdFor,
13658
13961
  inboundBody: () => inboundBody,
13962
+ injectStateDir: () => injectStateDir,
13659
13963
  isAuthorized: () => isAuthorized,
13660
13964
  isBareSpawn: () => isBareSpawn,
13661
13965
  isCaptainAlive: () => isCaptainAlive,
@@ -13671,6 +13975,7 @@ __export(dist_exports2, {
13671
13975
  isReadOnlyTopLevelCommand: () => isReadOnlyTopLevelCommand,
13672
13976
  isSideTitle: () => isSideTitle,
13673
13977
  isStickyAttention: () => isStickyAttention,
13978
+ isSystemPrompt: () => isSystemPrompt,
13674
13979
  isTurnAccepted: () => isTurnAccepted,
13675
13980
  isVersionUpgrade: () => isVersionUpgrade,
13676
13981
  joinUrl: () => joinUrl,
@@ -13716,6 +14021,7 @@ __export(dist_exports2, {
13716
14021
  programArgsBlock: () => programArgsBlock,
13717
14022
  projectHealth: () => projectHealth,
13718
14023
  projectRulesDir: () => projectRulesDir,
14024
+ pruneSeenRules: () => pruneSeenRules,
13719
14025
  pruneTopics: () => pruneTopics,
13720
14026
  purgeExpiredWorkItems: () => purgeExpiredWorkItems,
13721
14027
  readCaptainAddress: () => readCaptainAddress,
@@ -13723,11 +14029,13 @@ __export(dist_exports2, {
13723
14029
  readFromCursor: () => readFromCursor,
13724
14030
  readIndex: () => readIndex,
13725
14031
  readRunningMarker: () => readRunningMarker,
14032
+ readSeenRules: () => readSeenRules,
13726
14033
  readUserIntent: () => readUserIntent,
13727
14034
  realpathOrSelf: () => realpathOrSelf,
13728
14035
  reapCrewChildren: () => reapCrewChildren,
13729
14036
  reapOrphanedCrews: () => reapOrphanedCrews,
13730
14037
  reconcileLiveness: () => reconcileLiveness,
14038
+ recordSeenRules: () => recordSeenRules,
13731
14039
  recordSession: () => recordSession,
13732
14040
  recoverStall: () => recoverStall,
13733
14041
  reduce: () => reduce,
@@ -13749,6 +14057,7 @@ __export(dist_exports2, {
13749
14057
  resolveGateMode: () => resolveGateMode,
13750
14058
  resolveGatePolicy: () => resolveGatePolicy,
13751
14059
  resolveGateTools: () => resolveGateTools,
14060
+ resolveInjectProject: () => resolveInjectProject,
13752
14061
  resolveProject: () => resolveProject,
13753
14062
  resolveProjectRules: () => resolveProjectRules,
13754
14063
  resolveRouterCredentials: () => resolveRouterCredentials,
@@ -13788,6 +14097,7 @@ __export(dist_exports2, {
13788
14097
  screenHasSplashMarker: () => screenHasSplashMarker,
13789
14098
  screenHash: () => screenHash,
13790
14099
  searchRules: () => searchRules,
14100
+ selectPromptHits: () => selectPromptHits,
13791
14101
  sendRequest: () => sendRequest,
13792
14102
  setLastUserId: () => setLastUserId,
13793
14103
  setNotify: () => setNotify,
@@ -13813,8 +14123,11 @@ __export(dist_exports2, {
13813
14123
  topicName: () => topicName,
13814
14124
  tryAcquireDaemonLock: () => tryAcquireDaemonLock,
13815
14125
  usageFromJson: () => usageFromJson,
14126
+ validateKb: () => validateKb,
13816
14127
  waitForCaptainDelivery: () => waitForCaptainDelivery,
13817
14128
  waitForWarmup: () => waitForWarmup,
14129
+ wholeWordTerms: () => wholeWordTerms,
14130
+ withBudget: () => withBudget,
13818
14131
  writeCaptainAddress: () => writeCaptainAddress,
13819
14132
  writeCursor: () => writeCursor,
13820
14133
  writeExitMarker: () => writeExitMarker,
@@ -13878,7 +14191,7 @@ var init_dist2 = __esm({
13878
14191
  });
13879
14192
 
13880
14193
  // packages/agents/dist/claude/registry.js
13881
- import fs19 from "fs";
14194
+ import fs20 from "fs";
13882
14195
  import { join as join17 } from "path";
13883
14196
  import { homedir as homedir7 } from "os";
13884
14197
  function parseRegistryDir(files, readFile7) {
@@ -13923,11 +14236,11 @@ function readClaudeStatus(task) {
13923
14236
  return void 0;
13924
14237
  let files;
13925
14238
  try {
13926
- files = fs19.readdirSync(CLAUDE_SESSIONS_DIR);
14239
+ files = fs20.readdirSync(CLAUDE_SESSIONS_DIR);
13927
14240
  } catch {
13928
14241
  return void 0;
13929
14242
  }
13930
- const entries = parseRegistryDir(files, (name) => fs19.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
14243
+ const entries = parseRegistryDir(files, (name) => fs20.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
13931
14244
  let entry;
13932
14245
  if (task.messagingSocketPath) {
13933
14246
  entry = entries.find((e) => e.messagingSocketPath === task.messagingSocketPath);
@@ -13942,11 +14255,11 @@ function readClaudeStatus(task) {
13942
14255
  function readClaudeStatusByCwd(cwd) {
13943
14256
  let files;
13944
14257
  try {
13945
- files = fs19.readdirSync(CLAUDE_SESSIONS_DIR);
14258
+ files = fs20.readdirSync(CLAUDE_SESSIONS_DIR);
13946
14259
  } catch {
13947
14260
  return void 0;
13948
14261
  }
13949
- const entries = parseRegistryDir(files, (name) => fs19.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
14262
+ const entries = parseRegistryDir(files, (name) => fs20.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
13950
14263
  const entry = entries.find((e) => e.cwd === cwd);
13951
14264
  if (!entry)
13952
14265
  return void 0;
@@ -13955,11 +14268,11 @@ function readClaudeStatusByCwd(cwd) {
13955
14268
  function readClaudeStatusBySocketPath(socketPath2) {
13956
14269
  let files;
13957
14270
  try {
13958
- files = fs19.readdirSync(CLAUDE_SESSIONS_DIR);
14271
+ files = fs20.readdirSync(CLAUDE_SESSIONS_DIR);
13959
14272
  } catch {
13960
14273
  return void 0;
13961
14274
  }
13962
- const entries = parseRegistryDir(files, (name) => fs19.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
14275
+ const entries = parseRegistryDir(files, (name) => fs20.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
13963
14276
  const entry = entries.find((e) => e.messagingSocketPath === socketPath2);
13964
14277
  if (!entry)
13965
14278
  return void 0;
@@ -14382,8 +14695,8 @@ var init_registry2 = __esm({
14382
14695
  });
14383
14696
 
14384
14697
  // packages/agents/dist/drivers/launch-cmd.js
14385
- import fs20 from "fs";
14386
- import path18 from "path";
14698
+ import fs21 from "fs";
14699
+ import path19 from "path";
14387
14700
  function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model, templatesDir, messagingSocketPath, sessionName, thinking, captainBoot, settingsPath) {
14388
14701
  const driver = registry.getDriver(agentName);
14389
14702
  if (driver.name === "claude") {
@@ -14410,14 +14723,14 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
14410
14723
  cmd += ` --settings ${settingsPath}`;
14411
14724
  }
14412
14725
  if (templatesDir) {
14413
- const roleFile2 = path18.join(templatesDir, `${role}.claude.md`);
14414
- const legacyRoleFile = path18.join(templatesDir, `${role}.CLAUDE.md`);
14415
- const actualRoleFile = fs20.existsSync(roleFile2) ? roleFile2 : fs20.existsSync(legacyRoleFile) ? legacyRoleFile : null;
14726
+ const roleFile2 = path19.join(templatesDir, `${role}.claude.md`);
14727
+ const legacyRoleFile = path19.join(templatesDir, `${role}.CLAUDE.md`);
14728
+ const actualRoleFile = fs21.existsSync(roleFile2) ? roleFile2 : fs21.existsSync(legacyRoleFile) ? legacyRoleFile : null;
14416
14729
  if (actualRoleFile) {
14417
14730
  cmd += ` --append-system-prompt-file ${actualRoleFile}`;
14418
14731
  }
14419
- const pluginDir = path18.join(templatesDir, "..", "plugin");
14420
- if (fs20.existsSync(pluginDir)) {
14732
+ const pluginDir = path19.join(templatesDir, "..", "plugin");
14733
+ if (fs21.existsSync(pluginDir)) {
14421
14734
  cmd += ` --plugin-dir ${pluginDir}`;
14422
14735
  }
14423
14736
  }
@@ -14426,14 +14739,14 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
14426
14739
  }
14427
14740
  return cmd;
14428
14741
  }
14429
- const roleFile = templatesDir ? path18.join(templatesDir, `${role}.${driver.templateSuffix}.md`) : void 0;
14742
+ const roleFile = templatesDir ? path19.join(templatesDir, `${role}.${driver.templateSuffix}.md`) : void 0;
14430
14743
  return driver.buildCommand({
14431
14744
  prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,
14432
14745
  workdir: process.cwd(),
14433
14746
  role,
14434
14747
  model,
14435
14748
  autoApprove: true,
14436
- promptFile: roleFile && fs20.existsSync(roleFile) ? roleFile : void 0,
14749
+ promptFile: roleFile && fs21.existsSync(roleFile) ? roleFile : void 0,
14437
14750
  ...captainBoot && role === "captain" ? {
14438
14751
  interactive: true,
14439
14752
  ...captainBoot.port ? { port: captainBoot.port } : {},
@@ -14463,8 +14776,8 @@ var init_drivers = __esm({
14463
14776
 
14464
14777
  // packages/agents/dist/projection/cursor.js
14465
14778
  import { mkdir, readFile, writeFile } from "fs/promises";
14466
- import path19 from "path";
14467
- import os7 from "os";
14779
+ import path20 from "path";
14780
+ import os8 from "os";
14468
14781
  function renderMdc(source) {
14469
14782
  const skillSections = source.skills.map((s) => `## Skill: ${s.name}
14470
14783
 
@@ -14512,7 +14825,7 @@ function createCursorEmitter() {
14512
14825
  if (scope === "user") {
14513
14826
  return [
14514
14827
  {
14515
- path: path19.join(os7.homedir(), ".cursor/rules/squadrant-global.mdc"),
14828
+ path: path20.join(os8.homedir(), ".cursor/rules/squadrant-global.mdc"),
14516
14829
  shared: false,
14517
14830
  format: "mdc"
14518
14831
  }
@@ -14522,7 +14835,7 @@ function createCursorEmitter() {
14522
14835
  return [];
14523
14836
  return [
14524
14837
  {
14525
- path: path19.join(projectRoot, ".cursor/rules/squadrant.mdc"),
14838
+ path: path20.join(projectRoot, ".cursor/rules/squadrant.mdc"),
14526
14839
  shared: false,
14527
14840
  format: "mdc"
14528
14841
  }
@@ -14539,7 +14852,7 @@ function createCursorEmitter() {
14539
14852
  diff: buildDiff(existing, generated)
14540
14853
  };
14541
14854
  }
14542
- await mkdir(path19.dirname(dest.path), { recursive: true });
14855
+ await mkdir(path20.dirname(dest.path), { recursive: true });
14543
14856
  await writeFile(dest.path, generated, "utf-8");
14544
14857
  return {
14545
14858
  written: true,
@@ -14590,8 +14903,8 @@ var init_marker = __esm({
14590
14903
 
14591
14904
  // packages/agents/dist/projection/codex.js
14592
14905
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
14593
- import path20 from "path";
14594
- import os8 from "os";
14906
+ import path21 from "path";
14907
+ import os9 from "os";
14595
14908
  function renderMarkdown(source) {
14596
14909
  const skillSections = source.skills.map((s) => `## Skill: ${s.name}
14597
14910
 
@@ -14615,7 +14928,7 @@ function createCodexEmitter() {
14615
14928
  destinations(scope, projectRoot) {
14616
14929
  if (scope === "user") {
14617
14930
  return [{
14618
- path: path20.join(os8.homedir(), ".codex/AGENTS.md"),
14931
+ path: path21.join(os9.homedir(), ".codex/AGENTS.md"),
14619
14932
  shared: true,
14620
14933
  format: "markdown"
14621
14934
  }];
@@ -14623,7 +14936,7 @@ function createCodexEmitter() {
14623
14936
  if (!projectRoot)
14624
14937
  return [];
14625
14938
  return [{
14626
- path: path20.join(projectRoot, "AGENTS.md"),
14939
+ path: path21.join(projectRoot, "AGENTS.md"),
14627
14940
  shared: true,
14628
14941
  format: "markdown"
14629
14942
  }];
@@ -14644,7 +14957,7 @@ ${existing ?? ""}
14644
14957
  ${generated}`
14645
14958
  };
14646
14959
  }
14647
- await mkdir2(path20.dirname(dest.path), { recursive: true });
14960
+ await mkdir2(path21.dirname(dest.path), { recursive: true });
14648
14961
  await writeFile2(dest.path, generated, "utf-8");
14649
14962
  return {
14650
14963
  written: true,
@@ -14662,8 +14975,8 @@ var init_codex2 = __esm({
14662
14975
 
14663
14976
  // packages/agents/dist/projection/gemini.js
14664
14977
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
14665
- import path21 from "path";
14666
- import os9 from "os";
14978
+ import path22 from "path";
14979
+ import os10 from "os";
14667
14980
  function renderMarkdown2(source) {
14668
14981
  const skillSections = source.skills.map((s) => `## Skill: ${s.name}
14669
14982
 
@@ -14687,7 +15000,7 @@ function createGeminiEmitter() {
14687
15000
  destinations(scope, projectRoot) {
14688
15001
  if (scope === "user") {
14689
15002
  return [{
14690
- path: path21.join(os9.homedir(), ".gemini/GEMINI.md"),
15003
+ path: path22.join(os10.homedir(), ".gemini/GEMINI.md"),
14691
15004
  shared: true,
14692
15005
  format: "markdown"
14693
15006
  }];
@@ -14695,7 +15008,7 @@ function createGeminiEmitter() {
14695
15008
  if (!projectRoot)
14696
15009
  return [];
14697
15010
  return [{
14698
- path: path21.join(projectRoot, "GEMINI.md"),
15011
+ path: path22.join(projectRoot, "GEMINI.md"),
14699
15012
  shared: true,
14700
15013
  format: "markdown"
14701
15014
  }];
@@ -14716,7 +15029,7 @@ ${existing ?? ""}
14716
15029
  ${generated}`
14717
15030
  };
14718
15031
  }
14719
- await mkdir3(path21.dirname(dest.path), { recursive: true });
15032
+ await mkdir3(path22.dirname(dest.path), { recursive: true });
14720
15033
  await writeFile3(dest.path, generated, "utf-8");
14721
15034
  return {
14722
15035
  written: true,
@@ -14734,8 +15047,8 @@ var init_gemini2 = __esm({
14734
15047
 
14735
15048
  // packages/agents/dist/projection/opencode.js
14736
15049
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
14737
- import path22 from "path";
14738
- import os10 from "os";
15050
+ import path23 from "path";
15051
+ import os11 from "os";
14739
15052
  function renderMarkdown3(source) {
14740
15053
  const skillSections = source.skills.map((s) => `## Skill: ${s.name}
14741
15054
 
@@ -14759,7 +15072,7 @@ function createOpencodeEmitter() {
14759
15072
  destinations(scope, projectRoot) {
14760
15073
  if (scope === "user") {
14761
15074
  return [{
14762
- path: path22.join(os10.homedir(), ".config", "opencode", "AGENTS.md"),
15075
+ path: path23.join(os11.homedir(), ".config", "opencode", "AGENTS.md"),
14763
15076
  shared: true,
14764
15077
  format: "markdown"
14765
15078
  }];
@@ -14767,7 +15080,7 @@ function createOpencodeEmitter() {
14767
15080
  if (!projectRoot)
14768
15081
  return [];
14769
15082
  return [{
14770
- path: path22.join(projectRoot, "AGENTS.md"),
15083
+ path: path23.join(projectRoot, "AGENTS.md"),
14771
15084
  shared: true,
14772
15085
  format: "markdown"
14773
15086
  }];
@@ -14788,7 +15101,7 @@ ${existing ?? ""}
14788
15101
  ${generated}`
14789
15102
  };
14790
15103
  }
14791
- await mkdir4(path22.dirname(dest.path), { recursive: true });
15104
+ await mkdir4(path23.dirname(dest.path), { recursive: true });
14792
15105
  await writeFile4(dest.path, generated, "utf-8");
14793
15106
  return {
14794
15107
  written: true,
@@ -14805,12 +15118,12 @@ var init_opencode2 = __esm({
14805
15118
  });
14806
15119
 
14807
15120
  // packages/agents/dist/projection/opencode-skills.js
14808
- import fs21 from "fs";
14809
- import os11 from "os";
14810
- import path23 from "path";
15121
+ import fs22 from "fs";
15122
+ import os12 from "os";
15123
+ import path24 from "path";
14811
15124
  function defaultOpencodeSkillsRoot(env = process.env) {
14812
- const configHome = env.XDG_CONFIG_HOME || path23.join(os11.homedir(), ".config");
14813
- return path23.join(configHome, "opencode", "skills");
15125
+ const configHome = env.XDG_CONFIG_HOME || path24.join(os12.homedir(), ".config");
15126
+ return path24.join(configHome, "opencode", "skills");
14814
15127
  }
14815
15128
  function parseSkillName(raw) {
14816
15129
  const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
@@ -14824,62 +15137,62 @@ function parseSkillName(raw) {
14824
15137
  }
14825
15138
  function listSourceSkills(sourceSkillsDir) {
14826
15139
  const out = /* @__PURE__ */ new Map();
14827
- if (!fs21.existsSync(sourceSkillsDir))
15140
+ if (!fs22.existsSync(sourceSkillsDir))
14828
15141
  return out;
14829
- for (const entry of fs21.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
15142
+ for (const entry of fs22.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
14830
15143
  if (!entry.isDirectory())
14831
15144
  continue;
14832
- const skillPath = path23.join(sourceSkillsDir, entry.name, "SKILL.md");
14833
- if (!fs21.existsSync(skillPath))
15145
+ const skillPath = path24.join(sourceSkillsDir, entry.name, "SKILL.md");
15146
+ if (!fs22.existsSync(skillPath))
14834
15147
  continue;
14835
- const name = parseSkillName(fs21.readFileSync(skillPath, "utf-8"));
15148
+ const name = parseSkillName(fs22.readFileSync(skillPath, "utf-8"));
14836
15149
  if (name && SAFE_NAME.test(name))
14837
15150
  out.set(name, skillPath);
14838
15151
  }
14839
15152
  return out;
14840
15153
  }
14841
15154
  function hasMarker(dir) {
14842
- return fs21.existsSync(path23.join(dir, OPENCODE_SKILL_MARKER));
15155
+ return fs22.existsSync(path24.join(dir, OPENCODE_SKILL_MARKER));
14843
15156
  }
14844
15157
  function syncOpencodeSkills(opts) {
14845
15158
  const result = { written: [], unchanged: [], removed: [], skipped: [] };
14846
15159
  const wanted = listSourceSkills(opts.sourceSkillsDir);
14847
- if (wanted.size === 0 && !fs21.existsSync(opts.sourceSkillsDir))
15160
+ if (wanted.size === 0 && !fs22.existsSync(opts.sourceSkillsDir))
14848
15161
  return result;
14849
15162
  if (!opts.dryRun)
14850
- fs21.mkdirSync(opts.skillsRoot, { recursive: true });
15163
+ fs22.mkdirSync(opts.skillsRoot, { recursive: true });
14851
15164
  for (const [name, srcPath] of wanted) {
14852
- const targetDir = path23.join(opts.skillsRoot, name);
14853
- const targetSkill = path23.join(targetDir, "SKILL.md");
15165
+ const targetDir = path24.join(opts.skillsRoot, name);
15166
+ const targetSkill = path24.join(targetDir, "SKILL.md");
14854
15167
  const managed = hasMarker(targetDir);
14855
- if (fs21.existsSync(targetSkill) && !managed) {
15168
+ if (fs22.existsSync(targetSkill) && !managed) {
14856
15169
  result.skipped.push({ name, reason: "foreign-collision" });
14857
15170
  continue;
14858
15171
  }
14859
- const current = fs21.existsSync(targetSkill) ? fs21.readFileSync(targetSkill) : null;
14860
- if (current && current.equals(fs21.readFileSync(srcPath))) {
15172
+ const current = fs22.existsSync(targetSkill) ? fs22.readFileSync(targetSkill) : null;
15173
+ if (current && current.equals(fs22.readFileSync(srcPath))) {
14861
15174
  if (!managed && !opts.dryRun) {
14862
- fs21.writeFileSync(path23.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
15175
+ fs22.writeFileSync(path24.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
14863
15176
  }
14864
15177
  result.unchanged.push(name);
14865
15178
  continue;
14866
15179
  }
14867
15180
  if (!opts.dryRun) {
14868
- fs21.mkdirSync(targetDir, { recursive: true });
14869
- fs21.copyFileSync(srcPath, targetSkill);
14870
- fs21.writeFileSync(path23.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
15181
+ fs22.mkdirSync(targetDir, { recursive: true });
15182
+ fs22.copyFileSync(srcPath, targetSkill);
15183
+ fs22.writeFileSync(path24.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
14871
15184
  }
14872
15185
  result.written.push(name);
14873
15186
  }
14874
- if (fs21.existsSync(opts.skillsRoot)) {
14875
- for (const entry of fs21.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
15187
+ if (fs22.existsSync(opts.skillsRoot)) {
15188
+ for (const entry of fs22.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
14876
15189
  if (!entry.isDirectory() || wanted.has(entry.name))
14877
15190
  continue;
14878
- const dir = path23.join(opts.skillsRoot, entry.name);
15191
+ const dir = path24.join(opts.skillsRoot, entry.name);
14879
15192
  if (!hasMarker(dir))
14880
15193
  continue;
14881
15194
  if (!opts.dryRun)
14882
- fs21.rmSync(dir, { recursive: true, force: true });
15195
+ fs22.rmSync(dir, { recursive: true, force: true });
14883
15196
  result.removed.push(entry.name);
14884
15197
  }
14885
15198
  }
@@ -14887,7 +15200,7 @@ function syncOpencodeSkills(opts) {
14887
15200
  }
14888
15201
  function syncShippedOpencodeSkills(opts) {
14889
15202
  return syncOpencodeSkills({
14890
- sourceSkillsDir: path23.join(opts.pkgRoot, "plugin", "skills"),
15203
+ sourceSkillsDir: path24.join(opts.pkgRoot, "plugin", "skills"),
14891
15204
  skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
14892
15205
  dryRun: opts.dryRun
14893
15206
  });
@@ -14903,8 +15216,8 @@ var init_opencode_skills = __esm({
14903
15216
 
14904
15217
  // packages/agents/dist/projection/claude.js
14905
15218
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
14906
- import path24 from "path";
14907
- import os12 from "os";
15219
+ import path25 from "path";
15220
+ import os13 from "os";
14908
15221
  function renderMarkdown4(source) {
14909
15222
  const skillSections = source.skills.map((s) => `## Skill: ${s.name}
14910
15223
 
@@ -14928,7 +15241,7 @@ function createClaudeEmitter() {
14928
15241
  destinations(scope, projectRoot) {
14929
15242
  if (scope === "user") {
14930
15243
  return [{
14931
- path: path24.join(os12.homedir(), ".claude/CLAUDE.md"),
15244
+ path: path25.join(os13.homedir(), ".claude/CLAUDE.md"),
14932
15245
  shared: true,
14933
15246
  format: "markdown"
14934
15247
  }];
@@ -14936,7 +15249,7 @@ function createClaudeEmitter() {
14936
15249
  if (!projectRoot)
14937
15250
  return [];
14938
15251
  return [{
14939
- path: path24.join(projectRoot, "CLAUDE.md"),
15252
+ path: path25.join(projectRoot, "CLAUDE.md"),
14940
15253
  shared: true,
14941
15254
  format: "markdown"
14942
15255
  }];
@@ -14957,7 +15270,7 @@ ${existing ?? ""}
14957
15270
  ${generated}`
14958
15271
  };
14959
15272
  }
14960
- await mkdir5(path24.dirname(dest.path), { recursive: true });
15273
+ await mkdir5(path25.dirname(dest.path), { recursive: true });
14961
15274
  await writeFile5(dest.path, generated, "utf-8");
14962
15275
  return {
14963
15276
  written: true,
@@ -15019,12 +15332,12 @@ function _parseChunk(acc, chunk) {
15019
15332
  const out = [];
15020
15333
  let idx;
15021
15334
  while ((idx = acc.buf.indexOf("\n")) >= 0) {
15022
- const line = acc.buf.slice(0, idx);
15335
+ const line2 = acc.buf.slice(0, idx);
15023
15336
  acc.buf = acc.buf.slice(idx + 1);
15024
- if (!line.trim())
15337
+ if (!line2.trim())
15025
15338
  continue;
15026
15339
  try {
15027
- out.push(JSON.parse(line));
15340
+ out.push(JSON.parse(line2));
15028
15341
  } catch {
15029
15342
  }
15030
15343
  }
@@ -15785,9 +16098,9 @@ var init_sse_bridge = __esm({
15785
16098
  buf += decoder.decode(value, { stream: true });
15786
16099
  let nl;
15787
16100
  while ((nl = buf.indexOf("\n")) >= 0) {
15788
- const line = buf.slice(0, nl);
16101
+ const line2 = buf.slice(0, nl);
15789
16102
  buf = buf.slice(nl + 1);
15790
- this.handleLine(taskId, line);
16103
+ this.handleLine(taskId, line2);
15791
16104
  }
15792
16105
  }
15793
16106
  } finally {
@@ -15798,16 +16111,16 @@ var init_sse_bridge = __esm({
15798
16111
  }
15799
16112
  }
15800
16113
  handleLine(taskId, rawLine) {
15801
- let line = rawLine.trim();
15802
- if (!line)
16114
+ let line2 = rawLine.trim();
16115
+ if (!line2)
15803
16116
  return;
15804
- if (line.startsWith("data:"))
15805
- line = line.slice(5).trim();
15806
- if (!line.startsWith("{"))
16117
+ if (line2.startsWith("data:"))
16118
+ line2 = line2.slice(5).trim();
16119
+ if (!line2.startsWith("{"))
15807
16120
  return;
15808
16121
  let json2;
15809
16122
  try {
15810
- json2 = JSON.parse(line);
16123
+ json2 = JSON.parse(line2);
15811
16124
  } catch {
15812
16125
  return;
15813
16126
  }
@@ -15929,14 +16242,14 @@ function detectTrailingQuestion2(text) {
15929
16242
  let inFence = false;
15930
16243
  let lastLine = null;
15931
16244
  for (const raw of text.split(/\r?\n/)) {
15932
- const line = raw.trim();
15933
- if (line.startsWith("```")) {
16245
+ const line2 = raw.trim();
16246
+ if (line2.startsWith("```")) {
15934
16247
  inFence = !inFence;
15935
16248
  continue;
15936
16249
  }
15937
- if (inFence || line === "")
16250
+ if (inFence || line2 === "")
15938
16251
  continue;
15939
- lastLine = line;
16252
+ lastLine = line2;
15940
16253
  }
15941
16254
  if (lastLine && lastLine.endsWith("?"))
15942
16255
  return lastLine;
@@ -15953,12 +16266,12 @@ function readLastAssistantText(transcriptPath) {
15953
16266
  const raw = readFileSync14(transcriptPath, "utf-8");
15954
16267
  const lines = raw.split(/\r?\n/);
15955
16268
  for (let i = lines.length - 1; i >= 0; i--) {
15956
- const line = lines[i].trim();
15957
- if (!line)
16269
+ const line2 = lines[i].trim();
16270
+ if (!line2)
15958
16271
  continue;
15959
16272
  let entry;
15960
16273
  try {
15961
- entry = JSON.parse(line);
16274
+ entry = JSON.parse(line2);
15962
16275
  } catch {
15963
16276
  continue;
15964
16277
  }
@@ -15992,8 +16305,8 @@ function resolveLastAssistantText(payload) {
15992
16305
  const derived = deriveTranscriptPath(p?.session_id, cwd);
15993
16306
  if (derived)
15994
16307
  candidates.push(derived);
15995
- for (const path45 of candidates) {
15996
- const text = readLastAssistantText(path45);
16308
+ for (const path46 of candidates) {
16309
+ const text = readLastAssistantText(path46);
15997
16310
  if (text != null)
15998
16311
  return text;
15999
16312
  }
@@ -16261,9 +16574,9 @@ function isQuotedLine2(raw) {
16261
16574
  return QUOTED_PREFIX_RE2.test(noAnsi);
16262
16575
  }
16263
16576
  function stripChrome2(raw) {
16264
- let line = raw.replace(/\[[0-9;]*m/g, "");
16265
- line = line.replace(/^[\s│┃▏▕|]+/, "").replace(/[\s│┃▏▕|]+$/, "");
16266
- const trimmed = line.trim();
16577
+ let line2 = raw.replace(/\[[0-9;]*m/g, "");
16578
+ line2 = line2.replace(/^[\s│┃▏▕|]+/, "").replace(/[\s│┃▏▕|]+$/, "");
16579
+ const trimmed = line2.trim();
16267
16580
  if (trimmed === "")
16268
16581
  return null;
16269
16582
  if (PURE_CHROME_RE2.test(trimmed))
@@ -16637,13 +16950,13 @@ function buildUserEnvelope(opts) {
16637
16950
  };
16638
16951
  }
16639
16952
  function writeLine(socketPath2, envelope, deps) {
16640
- const line = `${JSON.stringify(envelope)}
16953
+ const line2 = `${JSON.stringify(envelope)}
16641
16954
  `;
16642
- if (Buffer.byteLength(line, "utf8") > MAX_LINE_BYTES) {
16955
+ if (Buffer.byteLength(line2, "utf8") > MAX_LINE_BYTES) {
16643
16956
  return Promise.resolve({
16644
16957
  ok: false,
16645
16958
  reason: "transport",
16646
- error: `line exceeds the receiver's 1 MiB buffer cap (${Buffer.byteLength(line, "utf8")} bytes)`
16959
+ error: `line exceeds the receiver's 1 MiB buffer cap (${Buffer.byteLength(line2, "utf8")} bytes)`
16647
16960
  });
16648
16961
  }
16649
16962
  return new Promise((resolve4) => {
@@ -16663,7 +16976,7 @@ function writeLine(socketPath2, envelope, deps) {
16663
16976
  done({ ok: false, reason: "transport", error: `timeout after ${deps.timeoutMs ?? DEFAULT_TIMEOUT_MS}ms` });
16664
16977
  }, deps.timeoutMs ?? DEFAULT_TIMEOUT_MS);
16665
16978
  sock.on("connect", () => {
16666
- sock.write(line, () => {
16979
+ sock.write(line2, () => {
16667
16980
  clearTimeout(timer);
16668
16981
  try {
16669
16982
  sock.end();
@@ -16840,20 +17153,20 @@ var init_receipt_listener = __esm({
16840
17153
  buf += chunk;
16841
17154
  let nl;
16842
17155
  while ((nl = buf.indexOf("\n")) !== -1) {
16843
- const line = buf.slice(0, nl);
17156
+ const line2 = buf.slice(0, nl);
16844
17157
  buf = buf.slice(nl + 1);
16845
- this.dispatch(line);
17158
+ this.dispatch(line2);
16846
17159
  }
16847
17160
  });
16848
17161
  conn.on("error", () => {
16849
17162
  });
16850
17163
  }
16851
- dispatch(line) {
16852
- if (!line.trim())
17164
+ dispatch(line2) {
17165
+ if (!line2.trim())
16853
17166
  return;
16854
17167
  let f;
16855
17168
  try {
16856
- f = JSON.parse(line);
17169
+ f = JSON.parse(line2);
16857
17170
  } catch {
16858
17171
  this.deps.log?.(`claude-receipt: discarded non-JSON frame`);
16859
17172
  return;
@@ -16882,22 +17195,22 @@ var init_receipt_listener = __esm({
16882
17195
  });
16883
17196
 
16884
17197
  // packages/agents/dist/claude/api-key-approval.js
16885
- import fs22 from "fs";
16886
- import os13 from "os";
16887
- import path25 from "path";
17198
+ import fs23 from "fs";
17199
+ import os14 from "os";
17200
+ import path26 from "path";
16888
17201
  function ensureClaudeApiKeyApproved(apiKey, opts = {}) {
16889
17202
  const suffix = apiKey.slice(-20);
16890
17203
  if (!suffix)
16891
17204
  return { changed: false, reason: "empty api key" };
16892
- const file = opts.claudeJsonPath ?? path25.join(os13.homedir(), ".claude.json");
17205
+ const file = opts.claudeJsonPath ?? path26.join(os14.homedir(), ".claude.json");
16893
17206
  const log = opts.log ?? (() => {
16894
17207
  });
16895
- if (!fs22.existsSync(file)) {
17208
+ if (!fs23.existsSync(file)) {
16896
17209
  return { changed: false, reason: "no ~/.claude.json yet \u2014 skipping routed-key pre-approval" };
16897
17210
  }
16898
17211
  let doc;
16899
17212
  try {
16900
- doc = JSON.parse(fs22.readFileSync(file, "utf8"));
17213
+ doc = JSON.parse(fs23.readFileSync(file, "utf8"));
16901
17214
  } catch {
16902
17215
  return {
16903
17216
  changed: false,
@@ -16919,11 +17232,11 @@ function ensureClaudeApiKeyApproved(apiKey, opts = {}) {
16919
17232
  };
16920
17233
  const tmp = `${file}.squadrant-tmp`;
16921
17234
  try {
16922
- fs22.writeFileSync(tmp, JSON.stringify(doc, null, 2) + "\n", { mode: fs22.statSync(file).mode & 511 });
16923
- fs22.renameSync(tmp, file);
17235
+ fs23.writeFileSync(tmp, JSON.stringify(doc, null, 2) + "\n", { mode: fs23.statSync(file).mode & 511 });
17236
+ fs23.renameSync(tmp, file);
16924
17237
  } catch (e) {
16925
17238
  try {
16926
- fs22.unlinkSync(tmp);
17239
+ fs23.unlinkSync(tmp);
16927
17240
  } catch {
16928
17241
  }
16929
17242
  return {
@@ -17032,10 +17345,10 @@ var init_http_channel = __esm({
17032
17345
  return cached;
17033
17346
  const directory = this.directoryFor?.(taskId);
17034
17347
  const createdAfterMs = this.createdAfterFor?.(taskId);
17035
- for (const path45 of ["/session?", "/api/session?"]) {
17348
+ for (const path46 of ["/session?", "/api/session?"]) {
17036
17349
  let res;
17037
17350
  try {
17038
- res = await this.request(`http://127.0.0.1:${port}${path45}`, { method: "GET" });
17351
+ res = await this.request(`http://127.0.0.1:${port}${path46}`, { method: "GET" });
17039
17352
  } catch {
17040
17353
  return void 0;
17041
17354
  }
@@ -17311,13 +17624,13 @@ function parseDraftFromScreen(screen) {
17311
17624
  if (topHR === -1)
17312
17625
  return null;
17313
17626
  const inputLines = lines.slice(topHR + 1, bottomHR);
17314
- for (const line of inputLines) {
17627
+ for (const line2 of inputLines) {
17315
17628
  let extracted;
17316
- const boxMatch = line.match(/│\s*[>❯]\s+(.*?)\s*│/);
17629
+ const boxMatch = line2.match(/│\s*[>❯]\s+(.*?)\s*│/);
17317
17630
  if (boxMatch) {
17318
17631
  extracted = boxMatch[1].trim();
17319
17632
  } else {
17320
- const plainMatch = line.match(/^\s*[>❯]\s*(.*)$/);
17633
+ const plainMatch = line2.match(/^\s*[>❯]\s*(.*)$/);
17321
17634
  if (plainMatch)
17322
17635
  extracted = plainMatch[1].trim();
17323
17636
  }
@@ -17396,8 +17709,8 @@ function parseModalOptions(screen) {
17396
17709
  return null;
17397
17710
  const OPTION_RE3 = /^\s*(❯)?\s*(\d+)\.\s*(.*?)\s*$/;
17398
17711
  const options = [];
17399
- for (const line of lines.slice(topHR + 1, bottomHR)) {
17400
- const m = line.match(OPTION_RE3);
17712
+ for (const line2 of lines.slice(topHR + 1, bottomHR)) {
17713
+ const m = line2.match(OPTION_RE3);
17401
17714
  if (!m)
17402
17715
  continue;
17403
17716
  options.push({ index: Number(m[2]), label: m[3], highlighted: m[1] === "\u276F" });
@@ -17455,8 +17768,8 @@ function readInputBoxRaw(screen, opts) {
17455
17768
  if (topHR === -1)
17456
17769
  return null;
17457
17770
  const parts = [];
17458
- for (const line of lines.slice(topHR + 1, bottomHR)) {
17459
- let s = line.replace(/│/g, " ");
17771
+ for (const line2 of lines.slice(topHR + 1, bottomHR)) {
17772
+ let s = line2.replace(/│/g, " ");
17460
17773
  s = s.replace(/^\s*[>❯]\s?/, "");
17461
17774
  s = s.replace(/\s*[▌█▔▎▏]+\s*$/, "");
17462
17775
  parts.push(s);
@@ -17984,13 +18297,13 @@ var init_notifiers = __esm({
17984
18297
  });
17985
18298
 
17986
18299
  // packages/workspaces/dist/workspaces/obsidian.js
17987
- import fs23 from "fs/promises";
18300
+ import fs24 from "fs/promises";
17988
18301
  import { existsSync as existsSync11 } from "fs";
17989
- import path26 from "path";
18302
+ import path27 from "path";
17990
18303
  function resolveInRoot(root, relative) {
17991
- const joined = path26.resolve(root, relative);
17992
- const normalized2 = path26.resolve(root) + path26.sep;
17993
- if (joined !== path26.resolve(root) && !joined.startsWith(normalized2)) {
18304
+ const joined = path27.resolve(root, relative);
18305
+ const normalized2 = path27.resolve(root) + path27.sep;
18306
+ if (joined !== path27.resolve(root) && !joined.startsWith(normalized2)) {
17994
18307
  throw new Error(`Path '${relative}' escapes workspace root`);
17995
18308
  }
17996
18309
  return joined;
@@ -18009,16 +18322,16 @@ function createObsidianDriver(scope) {
18009
18322
  };
18010
18323
  },
18011
18324
  async read(rel) {
18012
- return fs23.readFile(resolveInRoot(root, rel), "utf-8");
18325
+ return fs24.readFile(resolveInRoot(root, rel), "utf-8");
18013
18326
  },
18014
18327
  async write(rel, content) {
18015
18328
  const abs = resolveInRoot(root, rel);
18016
- await fs23.mkdir(path26.dirname(abs), { recursive: true });
18017
- await fs23.writeFile(abs, content);
18329
+ await fs24.mkdir(path27.dirname(abs), { recursive: true });
18330
+ await fs24.writeFile(abs, content);
18018
18331
  },
18019
18332
  async exists(rel) {
18020
18333
  try {
18021
- await fs23.access(resolveInRoot(root, rel));
18334
+ await fs24.access(resolveInRoot(root, rel));
18022
18335
  return true;
18023
18336
  } catch {
18024
18337
  return false;
@@ -18026,13 +18339,13 @@ function createObsidianDriver(scope) {
18026
18339
  },
18027
18340
  async list(rel) {
18028
18341
  try {
18029
- return await fs23.readdir(resolveInRoot(root, rel));
18342
+ return await fs24.readdir(resolveInRoot(root, rel));
18030
18343
  } catch {
18031
18344
  return [];
18032
18345
  }
18033
18346
  },
18034
18347
  async mkdir(rel) {
18035
- await fs23.mkdir(resolveInRoot(root, rel), { recursive: true });
18348
+ await fs24.mkdir(resolveInRoot(root, rel), { recursive: true });
18036
18349
  }
18037
18350
  };
18038
18351
  }
@@ -18186,18 +18499,18 @@ var init_events_bridge = __esm({
18186
18499
  this.buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
18187
18500
  let nl;
18188
18501
  while ((nl = this.buf.indexOf("\n")) >= 0) {
18189
- const line = this.buf.slice(0, nl);
18502
+ const line2 = this.buf.slice(0, nl);
18190
18503
  this.buf = this.buf.slice(nl + 1);
18191
- this.handleLine(line);
18504
+ this.handleLine(line2);
18192
18505
  }
18193
18506
  }
18194
18507
  handleLine(rawLine) {
18195
- const line = rawLine.trim();
18196
- if (!line || line[0] !== "{")
18508
+ const line2 = rawLine.trim();
18509
+ if (!line2 || line2[0] !== "{")
18197
18510
  return;
18198
18511
  let f;
18199
18512
  try {
18200
- f = JSON.parse(line);
18513
+ f = JSON.parse(line2);
18201
18514
  } catch {
18202
18515
  return;
18203
18516
  }
@@ -18446,9 +18759,9 @@ function defaultListFiles(dir) {
18446
18759
  return [];
18447
18760
  }
18448
18761
  }
18449
- function defaultReadFile(path45) {
18762
+ function defaultReadFile(path46) {
18450
18763
  try {
18451
- return readFileSync17(path45, "utf-8");
18764
+ return readFileSync17(path46, "utf-8");
18452
18765
  } catch {
18453
18766
  return void 0;
18454
18767
  }
@@ -18941,16 +19254,16 @@ function extractDetail(sub, payload) {
18941
19254
  }
18942
19255
  return void 0;
18943
19256
  }
18944
- function defaultReadFile2(path45) {
19257
+ function defaultReadFile2(path46) {
18945
19258
  try {
18946
- return readFileSync18(path45, "utf-8");
19259
+ return readFileSync18(path46, "utf-8");
18947
19260
  } catch {
18948
19261
  return void 0;
18949
19262
  }
18950
19263
  }
18951
- function defaultWriteFile(path45, content) {
18952
- mkdirSync8(path45.replace(/\/[^/]+$/, ""), { recursive: true });
18953
- writeFileSync11(path45, content, "utf-8");
19264
+ function defaultWriteFile(path46, content) {
19265
+ mkdirSync8(path46.replace(/\/[^/]+$/, ""), { recursive: true });
19266
+ writeFileSync11(path46, content, "utf-8");
18954
19267
  }
18955
19268
  var CLAUDE_HOOK_EVENTS, DEFAULT_CLI_CMD, FOREIGN_AUTO_GATE_MARKER, SUBAGENT_MODEL_KEY, SMALL_FAST_MODEL_KEY, NativeHookSource;
18956
19269
  var init_native_hook_source = __esm({
@@ -19379,9 +19692,9 @@ async function runRuntimeSend(arg1, arg2, opts, confirmOpts) {
19379
19692
  const resolved = resolveTarget(registry, config, target, !!opts.command);
19380
19693
  await needRef(resolved);
19381
19694
  const finalProject = opts.command ? config.commandName : target;
19382
- const { join: join37, dirname: dirname13 } = await import("path");
19695
+ const { join: join38, dirname: dirname13 } = await import("path");
19383
19696
  const { DEFAULT_CONFIG_PATH: DEFAULT_CONFIG_PATH2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
19384
- const stateRoot = join37(dirname13(DEFAULT_CONFIG_PATH2), "state");
19697
+ const stateRoot = join38(dirname13(DEFAULT_CONFIG_PATH2), "state");
19385
19698
  const seq2 = await appendCaptainMessage2({
19386
19699
  stateRoot,
19387
19700
  project: finalProject,
@@ -19483,6 +19796,20 @@ var init_runtime2 = __esm({
19483
19796
  }
19484
19797
  });
19485
19798
 
19799
+ // packages/cli/src/lib/suppress-sqlite-warning.ts
19800
+ function isSqliteExperimentalWarning(warning, type2) {
19801
+ const name = typeof warning === "object" && warning !== null ? warning.name : typeof type2 === "string" ? type2 : void 0;
19802
+ const message = typeof warning === "string" ? warning : warning?.message;
19803
+ return name === "ExperimentalWarning" && typeof message === "string" && /SQLite is an experimental feature/i.test(message);
19804
+ }
19805
+ var original = process.emitWarning.bind(process);
19806
+ process.emitWarning = ((warning, ...rest) => {
19807
+ const first = rest[0];
19808
+ const type2 = typeof first === "string" ? first : first?.type;
19809
+ if (isSqliteExperimentalWarning(warning, type2)) return;
19810
+ original(warning, ...rest);
19811
+ });
19812
+
19486
19813
  // packages/cli/src/index.ts
19487
19814
  init_dist();
19488
19815
  init_dist2();
@@ -19490,7 +19817,7 @@ init_dist3();
19490
19817
  import { Command as Command40 } from "commander";
19491
19818
  import { existsSync as existsSync14, readFileSync as readFileSync21 } from "fs";
19492
19819
  import { fileURLToPath as fileURLToPath6 } from "url";
19493
- import { dirname as dirname12, join as join36 } from "path";
19820
+ import { dirname as dirname12, join as join37 } from "path";
19494
19821
  import { homedir as homedir21 } from "os";
19495
19822
 
19496
19823
  // packages/cli/src/commands/doctor.ts
@@ -19501,9 +19828,9 @@ init_dist();
19501
19828
  init_dist4();
19502
19829
  import { Command } from "commander";
19503
19830
  import { execSync as execSync7 } from "child_process";
19504
- import fs24 from "fs";
19831
+ import fs25 from "fs";
19505
19832
  import { stat } from "fs/promises";
19506
- import path27 from "path";
19833
+ import path28 from "path";
19507
19834
  import chalk3 from "chalk";
19508
19835
 
19509
19836
  // packages/cli/src/commands/health-view.ts
@@ -19605,7 +19932,7 @@ function settingsHaveAgentTeams() {
19605
19932
  try {
19606
19933
  const home = process.env.HOME || "";
19607
19934
  const settings = JSON.parse(
19608
- fs24.readFileSync(`${home}/.claude/settings.json`, "utf-8")
19935
+ fs25.readFileSync(`${home}/.claude/settings.json`, "utf-8")
19609
19936
  );
19610
19937
  return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
19611
19938
  } catch {
@@ -19616,7 +19943,7 @@ function pluginInstalled(pluginKey) {
19616
19943
  try {
19617
19944
  const home = process.env.HOME || "";
19618
19945
  const plugins = JSON.parse(
19619
- fs24.readFileSync(
19946
+ fs25.readFileSync(
19620
19947
  `${home}/.claude/plugins/installed_plugins.json`,
19621
19948
  "utf-8"
19622
19949
  )
@@ -19640,9 +19967,9 @@ function tryGetVersion(cmd) {
19640
19967
  }
19641
19968
  function candidateGlobalInstalls(roots) {
19642
19969
  const out = [];
19643
- if (roots.npm) out.push({ manager: "npm", packageJsonPath: path27.join(roots.npm, "squadrant", "package.json") });
19644
- if (roots.pnpm) out.push({ manager: "pnpm", packageJsonPath: path27.join(roots.pnpm, "squadrant", "package.json") });
19645
- if (roots.yarn) out.push({ manager: "yarn", packageJsonPath: path27.join(roots.yarn, "node_modules", "squadrant", "package.json") });
19970
+ if (roots.npm) out.push({ manager: "npm", packageJsonPath: path28.join(roots.npm, "squadrant", "package.json") });
19971
+ if (roots.pnpm) out.push({ manager: "pnpm", packageJsonPath: path28.join(roots.pnpm, "squadrant", "package.json") });
19972
+ if (roots.yarn) out.push({ manager: "yarn", packageJsonPath: path28.join(roots.yarn, "node_modules", "squadrant", "package.json") });
19646
19973
  return out;
19647
19974
  }
19648
19975
  function findInstalledSquadrants(candidates, readVersion) {
@@ -19662,7 +19989,7 @@ ${lines.join("\n")}
19662
19989
  }
19663
19990
  function readPackageVersion(packageJsonPath) {
19664
19991
  try {
19665
- const pkg2 = JSON.parse(fs24.readFileSync(packageJsonPath, "utf-8"));
19992
+ const pkg2 = JSON.parse(fs25.readFileSync(packageJsonPath, "utf-8"));
19666
19993
  return typeof pkg2.version === "string" ? pkg2.version : null;
19667
19994
  } catch {
19668
19995
  return null;
@@ -19727,7 +20054,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
19727
20054
  ));
19728
20055
  checkOptional(
19729
20056
  "Obsidian installed",
19730
- commandExists("obsidian") || fs24.existsSync("/Applications/Obsidian.app"),
20057
+ commandExists("obsidian") || fs25.existsSync("/Applications/Obsidian.app"),
19731
20058
  "viewer for the hub vault; the vault is plain Markdown",
19732
20059
  "Install from: https://obsidian.md"
19733
20060
  );
@@ -19824,7 +20151,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
19824
20151
  const emitter = projectionRegistry.get(name);
19825
20152
  const [userDest] = emitter.destinations("user");
19826
20153
  if (!userDest) continue;
19827
- const dir = path27.dirname(userDest.path);
20154
+ const dir = path28.dirname(userDest.path);
19828
20155
  let status;
19829
20156
  try {
19830
20157
  await stat(dir);
@@ -19845,7 +20172,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
19845
20172
  results.push(
19846
20173
  check(
19847
20174
  "Squadrant config exists",
19848
- fs24.existsSync(
20175
+ fs25.existsSync(
19849
20176
  process.env.SQUADRANT_CONFIG || `${process.env.HOME}/.config/squadrant/config.json`
19850
20177
  ),
19851
20178
  "Run: squadrant init"
@@ -19929,9 +20256,9 @@ init_dist();
19929
20256
  init_dist4();
19930
20257
  init_dist();
19931
20258
  import { Command as Command2 } from "commander";
19932
- import fs25 from "fs";
19933
- import path28 from "path";
19934
- import os14 from "os";
20259
+ import fs26 from "fs";
20260
+ import path29 from "path";
20261
+ import os15 from "os";
19935
20262
  import readline from "readline";
19936
20263
  import chalk4 from "chalk";
19937
20264
 
@@ -20181,22 +20508,22 @@ function detectClaudeAuth(probe = {}) {
20181
20508
  // packages/cli/src/commands/init.ts
20182
20509
  init_dist3();
20183
20510
  function findPackageRoot() {
20184
- let dir = path28.dirname(new URL(import.meta.url).pathname);
20511
+ let dir = path29.dirname(new URL(import.meta.url).pathname);
20185
20512
  while (dir !== "/") {
20186
- if (fs25.existsSync(path28.join(dir, "package.json"))) return dir;
20187
- dir = path28.dirname(dir);
20513
+ if (fs26.existsSync(path29.join(dir, "package.json"))) return dir;
20514
+ dir = path29.dirname(dir);
20188
20515
  }
20189
20516
  return process.cwd();
20190
20517
  }
20191
20518
  function copyDirRecursive(src, dest) {
20192
- fs25.mkdirSync(dest, { recursive: true });
20193
- for (const entry of fs25.readdirSync(src, { withFileTypes: true })) {
20194
- const srcPath = path28.join(src, entry.name);
20195
- const destPath = path28.join(dest, entry.name);
20519
+ fs26.mkdirSync(dest, { recursive: true });
20520
+ for (const entry of fs26.readdirSync(src, { withFileTypes: true })) {
20521
+ const srcPath = path29.join(src, entry.name);
20522
+ const destPath = path29.join(dest, entry.name);
20196
20523
  if (entry.isDirectory()) {
20197
20524
  copyDirRecursive(srcPath, destPath);
20198
20525
  } else {
20199
- fs25.copyFileSync(srcPath, destPath);
20526
+ fs26.copyFileSync(srcPath, destPath);
20200
20527
  }
20201
20528
  }
20202
20529
  }
@@ -20238,7 +20565,7 @@ function warnIfNoAnthropic(preset, auth) {
20238
20565
  var initCommand = new Command2("init").description("Guided first-time setup: provider, hub vault, agents, plugins, projects (re-run-safe)").option("--hub <path>", "Hub vault path", "~/squadrant-hub").option("--preset <id>", "provider preset: a|b|c (non-interactive; d accepted as a deprecated alias for c)").action(async (opts) => {
20239
20566
  const hubPath = resolveHome(opts.hub);
20240
20567
  const pkgRoot = findPackageRoot();
20241
- const configDir = path28.join(os14.homedir(), ".config", "squadrant");
20568
+ const configDir = path29.join(os15.homedir(), ".config", "squadrant");
20242
20569
  const isTTY = process.stdin.isTTY === true;
20243
20570
  console.log(chalk4.bold("\nSquadrant Init\n"));
20244
20571
  let explicitPreset;
@@ -20276,8 +20603,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
20276
20603
  }
20277
20604
  const wsRegistry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
20278
20605
  try {
20279
- if (fs25.existsSync(DEFAULT_CONFIG_PATH)) {
20280
- const existing = JSON.parse(fs25.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
20606
+ if (fs26.existsSync(DEFAULT_CONFIG_PATH)) {
20607
+ const existing = JSON.parse(fs26.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
20281
20608
  wsRegistry.get(existing.workspace ?? "obsidian");
20282
20609
  }
20283
20610
  } catch (err) {
@@ -20285,7 +20612,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
20285
20612
  return;
20286
20613
  }
20287
20614
  stepHeader(1, 5, "Hub vault");
20288
- const configExists = fs25.existsSync(DEFAULT_CONFIG_PATH);
20615
+ const configExists = fs26.existsSync(DEFAULT_CONFIG_PATH);
20289
20616
  let config;
20290
20617
  if (configExists) {
20291
20618
  console.log(chalk4.yellow(" \u26A0 Config already exists, skipping creation"));
@@ -20323,37 +20650,37 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
20323
20650
  saveConfig(config);
20324
20651
  console.log(chalk4.green(` \u2714 Config updated at ${DEFAULT_CONFIG_PATH}`));
20325
20652
  }
20326
- const hubTemplate = path28.join(pkgRoot, "obsidian", "hub");
20327
- if (fs25.existsSync(hubPath)) {
20653
+ const hubTemplate = path29.join(pkgRoot, "obsidian", "hub");
20654
+ if (fs26.existsSync(hubPath)) {
20328
20655
  console.log(chalk4.yellow(` \u26A0 Hub vault already exists at ${hubPath}`));
20329
- } else if (fs25.existsSync(hubTemplate)) {
20656
+ } else if (fs26.existsSync(hubTemplate)) {
20330
20657
  copyDirRecursive(hubTemplate, hubPath);
20331
20658
  console.log(chalk4.green(` \u2714 Hub vault scaffolded at ${hubPath}`));
20332
20659
  } else {
20333
- fs25.mkdirSync(hubPath, { recursive: true });
20660
+ fs26.mkdirSync(hubPath, { recursive: true });
20334
20661
  console.log(chalk4.yellow(` \u26A0 Hub template not found; created empty directory at ${hubPath}`));
20335
20662
  }
20336
- const hubDashboardSrc = path28.join(pkgRoot, "obsidian", "hub", "dashboard.md");
20337
- const hubDashboardDest = path28.join(hubPath, "dashboard.md");
20338
- if (fs25.existsSync(hubDashboardSrc)) {
20339
- fs25.copyFileSync(hubDashboardSrc, hubDashboardDest);
20663
+ const hubDashboardSrc = path29.join(pkgRoot, "obsidian", "hub", "dashboard.md");
20664
+ const hubDashboardDest = path29.join(hubPath, "dashboard.md");
20665
+ if (fs26.existsSync(hubDashboardSrc)) {
20666
+ fs26.copyFileSync(hubDashboardSrc, hubDashboardDest);
20340
20667
  console.log(chalk4.green(` \u2714 Dashboard refreshed`));
20341
20668
  }
20342
- fs25.mkdirSync(path28.join(hubPath, "projects"), { recursive: true });
20669
+ fs26.mkdirSync(path29.join(hubPath, "projects"), { recursive: true });
20343
20670
  ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });
20344
20671
  console.log(chalk4.green(` \u2714 Runtime assets synced to ${configDir}`));
20345
20672
  stepHeader(2, 5, "Agent + projection setup");
20346
- const settingsPath = path28.join(os14.homedir(), ".claude", "settings.json");
20673
+ const settingsPath = path29.join(os15.homedir(), ".claude", "settings.json");
20347
20674
  try {
20348
20675
  let settings = {};
20349
- if (fs25.existsSync(settingsPath)) {
20350
- settings = JSON.parse(fs25.readFileSync(settingsPath, "utf-8"));
20676
+ if (fs26.existsSync(settingsPath)) {
20677
+ settings = JSON.parse(fs26.readFileSync(settingsPath, "utf-8"));
20351
20678
  }
20352
20679
  const env = settings.env || {};
20353
20680
  if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== "1") {
20354
20681
  settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" };
20355
- fs25.mkdirSync(path28.dirname(settingsPath), { recursive: true });
20356
- fs25.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
20682
+ fs26.mkdirSync(path29.dirname(settingsPath), { recursive: true });
20683
+ fs26.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
20357
20684
  console.log(chalk4.green(" \u2714 Agent Teams enabled in ~/.claude/settings.json"));
20358
20685
  } else {
20359
20686
  console.log(chalk4.green(" \u2714 Agent Teams already enabled"));
@@ -20406,7 +20733,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
20406
20733
  chalk4.cyan(" Absolute path to your first project (Enter to skip): ")
20407
20734
  );
20408
20735
  if (projectPath) {
20409
- const projectName = path28.basename(projectPath);
20736
+ const projectName = path29.basename(projectPath);
20410
20737
  console.log(chalk4.bold(`
20411
20738
  Run this to register it:`));
20412
20739
  console.log(chalk4.cyan(` squadrant projects add ${projectName} ${projectPath}
@@ -20434,8 +20761,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
20434
20761
  init_dist();
20435
20762
  init_dist2();
20436
20763
  import { Command as Command3 } from "commander";
20437
- import fs26 from "fs";
20438
- import path29 from "path";
20764
+ import fs27 from "fs";
20765
+ import path30 from "path";
20439
20766
  import chalk5 from "chalk";
20440
20767
  function restartAfterProjectsAdd(opts) {
20441
20768
  const doRestart = opts.doRestart ?? restartDaemonIfRunning;
@@ -20447,22 +20774,22 @@ function restartAfterProjectsAdd(opts) {
20447
20774
  }
20448
20775
  }
20449
20776
  function findPackageRoot2() {
20450
- let dir = path29.dirname(new URL(import.meta.url).pathname);
20777
+ let dir = path30.dirname(new URL(import.meta.url).pathname);
20451
20778
  while (dir !== "/") {
20452
- if (fs26.existsSync(path29.join(dir, "package.json"))) return dir;
20453
- dir = path29.dirname(dir);
20779
+ if (fs27.existsSync(path30.join(dir, "package.json"))) return dir;
20780
+ dir = path30.dirname(dir);
20454
20781
  }
20455
20782
  return process.cwd();
20456
20783
  }
20457
20784
  function copyDirRecursive2(src, dest) {
20458
- fs26.mkdirSync(dest, { recursive: true });
20459
- for (const entry of fs26.readdirSync(src, { withFileTypes: true })) {
20460
- const srcPath = path29.join(src, entry.name);
20461
- const destPath = path29.join(dest, entry.name);
20785
+ fs27.mkdirSync(dest, { recursive: true });
20786
+ for (const entry of fs27.readdirSync(src, { withFileTypes: true })) {
20787
+ const srcPath = path30.join(src, entry.name);
20788
+ const destPath = path30.join(dest, entry.name);
20462
20789
  if (entry.isDirectory()) {
20463
20790
  copyDirRecursive2(srcPath, destPath);
20464
20791
  } else {
20465
- fs26.copyFileSync(srcPath, destPath);
20792
+ fs27.copyFileSync(srcPath, destPath);
20466
20793
  }
20467
20794
  }
20468
20795
  }
@@ -20498,7 +20825,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
20498
20825
  process.exit(1);
20499
20826
  }
20500
20827
  const resolvedPath = resolveHome(projectPath);
20501
- if (!fs26.existsSync(path29.join(resolvedPath, ".git"))) {
20828
+ if (!fs27.existsSync(path30.join(resolvedPath, ".git"))) {
20502
20829
  console.log(chalk5.yellow(`
20503
20830
  \u26A0 No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.
20504
20831
  `));
@@ -20551,7 +20878,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
20551
20878
  \u26A0 Group '${group}' already has '${primary[0]}' as primary. Overriding.`));
20552
20879
  }
20553
20880
  }
20554
- const spokeVault = opts.spoke ? resolveHome(opts.spoke) : path29.join(config.hubVault, "spokes", name);
20881
+ const spokeVault = opts.spoke ? resolveHome(opts.spoke) : path30.join(config.hubVault, "spokes", name);
20555
20882
  const project = {
20556
20883
  path: resolvedPath,
20557
20884
  captainName,
@@ -20566,20 +20893,20 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
20566
20893
  \u2714 Project '${name}' registered`));
20567
20894
  restartAfterProjectsAdd({ noRestart: opts.restart === false });
20568
20895
  const pkgRoot = findPackageRoot2();
20569
- const spokeTemplate = path29.join(pkgRoot, "obsidian", "spoke");
20570
- if (fs26.existsSync(spokeVault)) {
20896
+ const spokeTemplate = path30.join(pkgRoot, "obsidian", "spoke");
20897
+ if (fs27.existsSync(spokeVault)) {
20571
20898
  console.log(chalk5.yellow(` \u26A0 Spoke vault already exists at ${spokeVault}, skipping scaffold`));
20572
- } else if (fs26.existsSync(spokeTemplate)) {
20899
+ } else if (fs27.existsSync(spokeTemplate)) {
20573
20900
  copyDirRecursive2(spokeTemplate, spokeVault);
20574
- const statusPath = path29.join(spokeVault, "status.md");
20575
- if (fs26.existsSync(statusPath)) {
20576
- const content = fs26.readFileSync(statusPath, "utf-8");
20901
+ const statusPath = path30.join(spokeVault, "status.md");
20902
+ if (fs27.existsSync(statusPath)) {
20903
+ const content = fs27.readFileSync(statusPath, "utf-8");
20577
20904
  const updated = content.replace(/^project: unnamed/m, `project: ${name}`);
20578
- fs26.writeFileSync(statusPath, updated);
20905
+ fs27.writeFileSync(statusPath, updated);
20579
20906
  }
20580
20907
  console.log(chalk5.green(` \u2714 Spoke vault scaffolded at ${spokeVault}`));
20581
20908
  } else {
20582
- fs26.mkdirSync(spokeVault, { recursive: true });
20909
+ fs27.mkdirSync(spokeVault, { recursive: true });
20583
20910
  console.log(chalk5.yellow(` \u26A0 Spoke template not found; created empty dir at ${spokeVault}`));
20584
20911
  }
20585
20912
  console.log("");
@@ -20648,10 +20975,10 @@ init_dist3();
20648
20975
  init_dist();
20649
20976
  import { Command as Command5 } from "commander";
20650
20977
  import { execSync as execSync9 } from "child_process";
20651
- import path30 from "path";
20652
- import os15 from "os";
20978
+ import path31 from "path";
20979
+ import os16 from "os";
20653
20980
  import chalk7 from "chalk";
20654
- var TEMPLATES_DIR2 = path30.join(os15.homedir(), ".config", "squadrant", "templates");
20981
+ var TEMPLATES_DIR2 = path31.join(os16.homedir(), ".config", "squadrant", "templates");
20655
20982
  var TASK_PROMPTS = {
20656
20983
  briefing: "Run your daily briefing using the squadrant:command-ops skill. Read all spoke handoffs, yesterday's logs, current status; produce a concise cross-project briefing; save to {hubVault}/daily-logs/YYYY-MM-DD.md; then exit.",
20657
20984
  "learnings-review": "Run a learnings review using the squadrant:command-ops skill. Scan {spokeVault}/learnings across all projects, identify cross-project patterns, propose captured-skill or fix actions, and exit when done.",
@@ -20684,7 +21011,7 @@ async function runCommandSpawn(input) {
20684
21011
  if (!agent) {
20685
21012
  throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
20686
21013
  }
20687
- const promptFile = path30.join(TEMPLATES_DIR2, `command.${agent.templateSuffix}.md`);
21014
+ const promptFile = path31.join(TEMPLATES_DIR2, `command.${agent.templateSuffix}.md`);
20688
21015
  const cliCommand = agent.buildCommand({
20689
21016
  prompt,
20690
21017
  workdir: process.cwd(),
@@ -20740,10 +21067,10 @@ function tailLines(text, maxLines = 40, maxBytes = 4096) {
20740
21067
  if (Buffer.byteLength(result, "utf-8") > maxBytes) {
20741
21068
  const truncated = [];
20742
21069
  let bytes = 0;
20743
- for (const line of kept) {
20744
- const lineBytes = Buffer.byteLength(line, "utf-8") + 1;
21070
+ for (const line2 of kept) {
21071
+ const lineBytes = Buffer.byteLength(line2, "utf-8") + 1;
20745
21072
  if (bytes + lineBytes > maxBytes) break;
20746
- truncated.push(line);
21073
+ truncated.push(line2);
20747
21074
  bytes += lineBytes;
20748
21075
  }
20749
21076
  result = truncated.join("\n");
@@ -21593,7 +21920,7 @@ async function runCrewSend2(project, name, message, opts) {
21593
21920
  socketPathFor: (taskId) => tasks.find((t) => t.id === taskId)?.messagingSocketPath,
21594
21921
  sessionIdFor: (taskId) => tasks.find((t) => t.id === taskId)?.sessionId,
21595
21922
  statusFor: (taskId) => readClaudeStatus(tasks.find((t) => t.id === taskId)),
21596
- wire: (p, e) => writeLine(p, e, { connect: (path45) => netConnect(path45) }),
21923
+ wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect(path46) }),
21597
21924
  receipts,
21598
21925
  newMsgId: () => randomUUID6(),
21599
21926
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
@@ -21980,11 +22307,11 @@ init_dist4();
21980
22307
  init_dist();
21981
22308
  init_dist2();
21982
22309
  import { Command as Command12 } from "commander";
21983
- import fs27 from "fs";
21984
- import path31 from "path";
21985
- import os16 from "os";
22310
+ import fs28 from "fs";
22311
+ import path32 from "path";
22312
+ import os17 from "os";
21986
22313
  import chalk12 from "chalk";
21987
- var TEMPLATES_DIR3 = path31.join(os16.homedir(), ".config", "squadrant", "templates");
22314
+ var TEMPLATES_DIR3 = path32.join(os17.homedir(), ".config", "squadrant", "templates");
21988
22315
  async function runSideSpawn2(input) {
21989
22316
  const config = loadConfig();
21990
22317
  const proj = config.projects[input.project];
@@ -22009,7 +22336,7 @@ async function runSideSpawn2(input) {
22009
22336
  }
22010
22337
  const sideModel = sideRole?.model;
22011
22338
  const sideThinking = sideRole?.thinking;
22012
- const promptFile = path31.join(
22339
+ const promptFile = path32.join(
22013
22340
  TEMPLATES_DIR3,
22014
22341
  `side.${input.role}.${agent.templateSuffix}.md`
22015
22342
  );
@@ -22017,7 +22344,7 @@ async function runSideSpawn2(input) {
22017
22344
  prompt: input.topic,
22018
22345
  workdir: spawnCwd,
22019
22346
  role: "side",
22020
- promptFile: fs27.existsSync(promptFile) ? promptFile : void 0,
22347
+ promptFile: fs28.existsSync(promptFile) ? promptFile : void 0,
22021
22348
  interactive: true,
22022
22349
  permissionMode: config.defaults.permissions?.crew ?? "auto",
22023
22350
  ...sideModel ? { model: sideModel } : {},
@@ -22236,9 +22563,9 @@ function formatAge(lastChecked, now) {
22236
22563
  return "stale";
22237
22564
  }
22238
22565
  function firstLine(s) {
22239
- for (const line of s.split(/\r?\n/)) {
22240
- if (line.trim().length > 0)
22241
- return line.trim();
22566
+ for (const line2 of s.split(/\r?\n/)) {
22567
+ if (line2.trim().length > 0)
22568
+ return line2.trim();
22242
22569
  }
22243
22570
  return "";
22244
22571
  }
@@ -22280,8 +22607,8 @@ function renderDashboard(rows, opts) {
22280
22607
 
22281
22608
  // packages/web/dist/sync-hub.js
22282
22609
  init_dist();
22283
- import fs28 from "fs";
22284
- import path32 from "path";
22610
+ import fs29 from "fs";
22611
+ import path33 from "path";
22285
22612
  function buildMirrorMarkdown(s) {
22286
22613
  const fenced = "```";
22287
22614
  return [
@@ -22307,15 +22634,15 @@ function buildMirrorMarkdown(s) {
22307
22634
  function syncHub(deps) {
22308
22635
  if (!deps.config.hubVault)
22309
22636
  return [];
22310
- const writeFile6 = deps.writeFile ?? ((p, c) => fs28.writeFileSync(p, c));
22311
- const mkdir6 = deps.mkdir ?? ((p) => fs28.mkdirSync(p, { recursive: true }));
22312
- const projectsDir = path32.join(resolveHome(deps.config.hubVault), "projects");
22637
+ const writeFile6 = deps.writeFile ?? ((p, c) => fs29.writeFileSync(p, c));
22638
+ const mkdir6 = deps.mkdir ?? ((p) => fs29.mkdirSync(p, { recursive: true }));
22639
+ const projectsDir = path33.join(resolveHome(deps.config.hubVault), "projects");
22313
22640
  mkdir6(projectsDir);
22314
22641
  const out = [];
22315
22642
  for (const s of deps.statuses) {
22316
22643
  if (s.state === "unknown")
22317
22644
  continue;
22318
- const hubPath = path32.join(projectsDir, `${s.project}.md`);
22645
+ const hubPath = path33.join(projectsDir, `${s.project}.md`);
22319
22646
  try {
22320
22647
  writeFile6(hubPath, buildMirrorMarkdown(s));
22321
22648
  out.push({ project: s.project, hubPath });
@@ -23321,18 +23648,18 @@ function renderHtml(snap, opts = {}) {
23321
23648
  import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync4 } from "fs";
23322
23649
  var LOG_TAIL_BYTES = 256 * 1024;
23323
23650
  var LOG_RING_SIZE = 1e3;
23324
- function defaultSize(path45) {
23651
+ function defaultSize(path46) {
23325
23652
  try {
23326
- return statSync4(path45).size;
23653
+ return statSync4(path46).size;
23327
23654
  } catch {
23328
23655
  return 0;
23329
23656
  }
23330
23657
  }
23331
- function defaultRead(path45, start, len) {
23658
+ function defaultRead(path46, start, len) {
23332
23659
  if (len <= 0)
23333
23660
  return "";
23334
23661
  try {
23335
- const fd = openSync3(path45, "r");
23662
+ const fd = openSync3(path46, "r");
23336
23663
  try {
23337
23664
  const buf = Buffer.alloc(len);
23338
23665
  const n = readSync2(fd, buf, 0, len, start);
@@ -23352,8 +23679,8 @@ var LogTailer = class {
23352
23679
  ring = [];
23353
23680
  size;
23354
23681
  read;
23355
- constructor(path45, ringSize = LOG_RING_SIZE, deps = {}) {
23356
- this.path = path45;
23682
+ constructor(path46, ringSize = LOG_RING_SIZE, deps = {}) {
23683
+ this.path = path46;
23357
23684
  this.ringSize = ringSize;
23358
23685
  this.size = deps.size ?? defaultSize;
23359
23686
  this.read = deps.read ?? defaultRead;
@@ -23629,9 +23956,9 @@ init_dist4();
23629
23956
  init_dist2();
23630
23957
  import { Command as Command14 } from "commander";
23631
23958
  import { execSync as execSync11, execFileSync as execFileSync11 } from "child_process";
23632
- import fs29 from "fs";
23633
- import path33 from "path";
23634
- import os17 from "os";
23959
+ import fs30 from "fs";
23960
+ import path34 from "path";
23961
+ import os18 from "os";
23635
23962
  import chalk15 from "chalk";
23636
23963
 
23637
23964
  // packages/cli/src/commands/launch-interactive.ts
@@ -23723,8 +24050,8 @@ function resolveLaunchBackend(o) {
23723
24050
  // packages/cli/src/commands/launch.ts
23724
24051
  init_dist2();
23725
24052
  var CMUX_APP = "/Applications/cmux.app";
23726
- var TEMPLATES_DIR4 = path33.join(os17.homedir(), ".config", "squadrant", "templates");
23727
- var SESSIONS_PATH2 = path33.join(os17.homedir(), ".config", "squadrant", "sessions.json");
24053
+ var TEMPLATES_DIR4 = path34.join(os18.homedir(), ".config", "squadrant", "templates");
24054
+ var SESSIONS_PATH2 = path34.join(os18.homedir(), ".config", "squadrant", "sessions.json");
23728
24055
  function shouldWireCaptainChannel(agentName, config) {
23729
24056
  return agentName === "claude" && resolveCaptainChannelMode(config.defaults) !== "off";
23730
24057
  }
@@ -23821,7 +24148,7 @@ var launchCommand = new Command14("launch").description(
23821
24148
  initialPrompt = "Run your startup checklist: use the squadrant:command-ops skill, complete your daily briefing, then report ready.";
23822
24149
  }
23823
24150
  const runtime = projectName ? runtimes.forProject(projectName, config) : runtimes.global(config);
23824
- const stateRoot = path33.join(os17.homedir(), ".config", "squadrant", "state");
24151
+ const stateRoot = path34.join(os18.homedir(), ".config", "squadrant", "state");
23825
24152
  const isOpencodeCaptain = role === "captain" && agentName === "opencode" && !!projectName;
23826
24153
  if (isOpencodeCaptain && !isOpencodeCaptainDir(cwd)) {
23827
24154
  console.error(chalk15.red(`
@@ -23974,12 +24301,12 @@ var launchCommand = new Command14("launch").description(
23974
24301
  }
23975
24302
  if (opts.all) {
23976
24303
  const hubPath = resolveHome(config.hubVault);
23977
- fs29.mkdirSync(hubPath, { recursive: true });
24304
+ fs30.mkdirSync(hubPath, { recursive: true });
23978
24305
  console.log(chalk15.bold("\nLaunching all captain workspaces\n"));
23979
24306
  for (const [name, proj] of Object.entries(config.projects)) {
23980
24307
  const projPath = resolveHome(proj.path);
23981
24308
  const spokePath = resolveHome(proj.spokeVault);
23982
- if (!fs29.existsSync(spokePath)) {
24309
+ if (!fs30.existsSync(spokePath)) {
23983
24310
  const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
23984
24311
  await ensureSpokeLayout(spokeDriver);
23985
24312
  console.log(chalk15.cyan(` \u2714 Created spoke vault at ${spokePath}`));
@@ -24017,7 +24344,7 @@ Launching ${selected.length} captain workspace(s) in parallel
24017
24344
  const proj = config.projects[name];
24018
24345
  const projPath = resolveHome(proj.path);
24019
24346
  const spokePath = resolveHome(proj.spokeVault);
24020
- if (!fs29.existsSync(spokePath)) {
24347
+ if (!fs30.existsSync(spokePath)) {
24021
24348
  const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
24022
24349
  await ensureSpokeLayout(spokeDriver);
24023
24350
  console.log(chalk15.cyan(` \u2714 Created spoke vault at ${spokePath}`));
@@ -24041,7 +24368,7 @@ Launching ${selected.length} captain workspace(s) in parallel
24041
24368
  const proj = config.projects[project];
24042
24369
  const projPath = resolveHome(proj.path);
24043
24370
  const spokePath = resolveHome(proj.spokeVault);
24044
- if (!fs29.existsSync(spokePath)) {
24371
+ if (!fs30.existsSync(spokePath)) {
24045
24372
  const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);
24046
24373
  await ensureSpokeLayout(spokeDriver);
24047
24374
  console.log(chalk15.cyan(` \u2714 Created spoke vault at ${spokePath}`));
@@ -24177,24 +24504,24 @@ Shutting down captain workspace for '${project}'...
24177
24504
  // packages/cli/src/commands/feedback.ts
24178
24505
  init_dist();
24179
24506
  import { Command as Command16 } from "commander";
24180
- import fs30 from "fs";
24181
- import os18 from "os";
24182
- import path34 from "path";
24507
+ import fs31 from "fs";
24508
+ import os19 from "os";
24509
+ import path35 from "path";
24183
24510
  import { fileURLToPath as fileURLToPath3 } from "url";
24184
24511
  import { execSync as execSync12 } from "child_process";
24185
24512
  import chalk17 from "chalk";
24186
24513
  var REPO_URL = "https://github.com/tu11aa/squadrant";
24187
24514
  function readPkgVersion() {
24188
24515
  try {
24189
- const pkgPath = path34.join(path34.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
24190
- return JSON.parse(fs30.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
24516
+ const pkgPath = path35.join(path35.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
24517
+ return JSON.parse(fs31.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
24191
24518
  } catch {
24192
24519
  return "unknown";
24193
24520
  }
24194
24521
  }
24195
24522
  function readMetrics(metricsPath) {
24196
24523
  try {
24197
- return JSON.parse(fs30.readFileSync(metricsPath, "utf-8"));
24524
+ return JSON.parse(fs31.readFileSync(metricsPath, "utf-8"));
24198
24525
  } catch {
24199
24526
  return {};
24200
24527
  }
@@ -24232,7 +24559,7 @@ function buildIssueUrl(metrics, squadrantVersion) {
24232
24559
  }
24233
24560
  var feedbackCommand = new Command16("feedback").description("Open a pre-filled GitHub issue for feedback or bug reports").action(() => {
24234
24561
  const config = loadConfig();
24235
- const metricsPath = config.metrics?.path || path34.join(os18.homedir(), ".config", "squadrant", "metrics.json");
24562
+ const metricsPath = config.metrics?.path || path35.join(os19.homedir(), ".config", "squadrant", "metrics.json");
24236
24563
  const metrics = readMetrics(metricsPath);
24237
24564
  const version = readStamp(config) ?? readPkgVersion();
24238
24565
  const issueUrl = buildIssueUrl(metrics, version);
@@ -24532,9 +24859,9 @@ workspaceCommand.command("read").description("Print the contents of a scope-rela
24532
24859
  const config = loadConfig();
24533
24860
  const registry = buildRegistry2();
24534
24861
  try {
24535
- const { projectTarget, path: path45 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24862
+ const { projectTarget, path: path46 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24536
24863
  const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
24537
- const content = await driver.read(path45);
24864
+ const content = await driver.read(path46);
24538
24865
  process.stdout.write(content);
24539
24866
  } catch (err) {
24540
24867
  console.error(chalk20.red(err.message));
@@ -24546,26 +24873,26 @@ workspaceCommand.command("write").description("Write content to a scope-relative
24546
24873
  const registry = buildRegistry2();
24547
24874
  try {
24548
24875
  let projectTarget;
24549
- let path45;
24876
+ let path46;
24550
24877
  let rawContent;
24551
24878
  if (opts.hub) {
24552
24879
  if (arg3 !== void 0) {
24553
24880
  throw new Error("With --hub, pass only the path and content");
24554
24881
  }
24555
24882
  projectTarget = void 0;
24556
- path45 = arg1;
24883
+ path46 = arg1;
24557
24884
  rawContent = arg2;
24558
24885
  } else {
24559
24886
  if (arg3 === void 0) {
24560
24887
  throw new Error("Missing content \u2014 usage: <project> <path> <content>");
24561
24888
  }
24562
24889
  projectTarget = arg1;
24563
- path45 = arg2;
24890
+ path46 = arg2;
24564
24891
  rawContent = arg3;
24565
24892
  }
24566
24893
  const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
24567
24894
  const payload = rawContent === "-" ? await readStdin() : rawContent;
24568
- await driver.write(path45, payload);
24895
+ await driver.write(path46, payload);
24569
24896
  } catch (err) {
24570
24897
  console.error(chalk20.red(err.message));
24571
24898
  process.exit(1);
@@ -24575,9 +24902,9 @@ workspaceCommand.command("list").description("List entries in a scope-relative d
24575
24902
  const config = loadConfig();
24576
24903
  const registry = buildRegistry2();
24577
24904
  try {
24578
- const { projectTarget, path: path45 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24905
+ const { projectTarget, path: path46 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24579
24906
  const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
24580
- const entries = await driver.list(path45);
24907
+ const entries = await driver.list(path46);
24581
24908
  for (const entry of entries) console.log(entry);
24582
24909
  } catch (err) {
24583
24910
  console.error(chalk20.red(err.message));
@@ -24588,9 +24915,9 @@ workspaceCommand.command("exists").description("Exit 0 if path exists, 1 if not"
24588
24915
  const config = loadConfig();
24589
24916
  const registry = buildRegistry2();
24590
24917
  try {
24591
- const { projectTarget, path: path45 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24918
+ const { projectTarget, path: path46 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24592
24919
  const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
24593
- const ok2 = await driver.exists(path45);
24920
+ const ok2 = await driver.exists(path46);
24594
24921
  process.exit(ok2 ? 0 : 1);
24595
24922
  } catch (err) {
24596
24923
  console.error(chalk20.red(err.message));
@@ -24601,9 +24928,9 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
24601
24928
  const config = loadConfig();
24602
24929
  const registry = buildRegistry2();
24603
24930
  try {
24604
- const { projectTarget, path: path45 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24931
+ const { projectTarget, path: path46 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
24605
24932
  const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
24606
- await driver.mkdir(path45);
24933
+ await driver.mkdir(path46);
24607
24934
  } catch (err) {
24608
24935
  console.error(chalk20.red(err.message));
24609
24936
  process.exit(1);
@@ -24642,8 +24969,8 @@ init_dist4();
24642
24969
  init_dist();
24643
24970
  import { Command as Command21 } from "commander";
24644
24971
  import chalk22 from "chalk";
24645
- import fs31 from "fs";
24646
- import path35 from "path";
24972
+ import fs32 from "fs";
24973
+ import path36 from "path";
24647
24974
  import { fileURLToPath as fileURLToPath4 } from "url";
24648
24975
  function parseScope(v2) {
24649
24976
  if (v2 !== "user" && v2 !== "project") {
@@ -24652,10 +24979,10 @@ function parseScope(v2) {
24652
24979
  return v2;
24653
24980
  }
24654
24981
  function findPackageRoot3() {
24655
- let dir = path35.dirname(fileURLToPath4(import.meta.url));
24982
+ let dir = path36.dirname(fileURLToPath4(import.meta.url));
24656
24983
  while (dir !== "/" && dir !== "") {
24657
- if (fs31.existsSync(path35.join(dir, "package.json"))) return dir;
24658
- dir = path35.dirname(dir);
24984
+ if (fs32.existsSync(path36.join(dir, "package.json"))) return dir;
24985
+ dir = path36.dirname(dir);
24659
24986
  }
24660
24987
  return process.cwd();
24661
24988
  }
@@ -24851,12 +25178,12 @@ init_dist();
24851
25178
  init_dist();
24852
25179
  init_dist2();
24853
25180
  import { Command as Command23 } from "commander";
24854
- import fs32 from "fs";
25181
+ import fs33 from "fs";
24855
25182
  import { fileURLToPath as fileURLToPath5 } from "url";
24856
25183
  import { dirname as dirname8, join as join30 } from "path";
24857
25184
  import chalk23 from "chalk";
24858
25185
  function runConfigCheck(opts) {
24859
- const raw = JSON.parse(fs32.readFileSync(opts.configPath, "utf-8"));
25186
+ const raw = JSON.parse(fs33.readFileSync(opts.configPath, "utf-8"));
24860
25187
  const def = getDefaultConfig();
24861
25188
  const items = detectDrift(raw, def);
24862
25189
  let working = raw;
@@ -24944,7 +25271,7 @@ function printItems(items) {
24944
25271
  var configCommand = new Command23("config").description("Inspect and reconcile squadrant config");
24945
25272
  configCommand.command("check").description("Detect config drift vs the current default schema").option("--fix", "Apply the safe tier (add missing, remove deprecated)", false).option("--accept", "Stamp the current version without changing config (dismiss advisories)", false).option("--json", "Output drift items as JSON", false).action((opts) => {
24946
25273
  const pkgVersion = readPkgVersion2();
24947
- if (!fs32.existsSync(DEFAULT_CONFIG_PATH)) {
25274
+ if (!fs33.existsSync(DEFAULT_CONFIG_PATH)) {
24948
25275
  console.log(chalk23.yellow("No config found \u2014 run `squadrant init` first."));
24949
25276
  return;
24950
25277
  }
@@ -24990,7 +25317,7 @@ configCommand.command("set").description("Write a config value by dotted key (e.
24990
25317
  });
24991
25318
  function readPkgVersion2() {
24992
25319
  const pkgPath = join30(dirname8(fileURLToPath5(import.meta.url)), "..", "package.json");
24993
- return JSON.parse(fs32.readFileSync(pkgPath, "utf-8")).version;
25320
+ return JSON.parse(fs33.readFileSync(pkgPath, "utf-8")).version;
24994
25321
  }
24995
25322
 
24996
25323
  // packages/cli/src/commands/heal.ts
@@ -25330,7 +25657,7 @@ import chalk28 from "chalk";
25330
25657
  init_dist3();
25331
25658
  init_dist2();
25332
25659
  import { createServer as createServer6, connect as netConnect2 } from "net";
25333
- import fs33 from "fs";
25660
+ import fs34 from "fs";
25334
25661
  import { join as join32 } from "path";
25335
25662
  import { randomUUID as randomUUID7 } from "crypto";
25336
25663
  import chalk27 from "chalk";
@@ -25338,15 +25665,15 @@ var shared;
25338
25665
  var registryEntryPath = () => join32(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
25339
25666
  function unregisterSenderIdentity() {
25340
25667
  try {
25341
- fs33.unlinkSync(registryEntryPath());
25668
+ fs34.unlinkSync(registryEntryPath());
25342
25669
  } catch {
25343
25670
  }
25344
25671
  }
25345
25672
  function registerSenderIdentity(socketPath2) {
25346
25673
  try {
25347
25674
  unregisterSenderIdentity();
25348
- fs33.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
25349
- fs33.writeFileSync(
25675
+ fs34.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
25676
+ fs34.writeFileSync(
25350
25677
  registryEntryPath(),
25351
25678
  JSON.stringify({
25352
25679
  pid: process.pid,
@@ -25372,7 +25699,7 @@ async function sharedReceiptListener() {
25372
25699
  // must never be the reason we refuse to start.
25373
25700
  unlinkStale: (p) => {
25374
25701
  try {
25375
- fs33.unlinkSync(p);
25702
+ fs34.unlinkSync(p);
25376
25703
  } catch {
25377
25704
  }
25378
25705
  },
@@ -25397,7 +25724,7 @@ async function buildCaptainChannel() {
25397
25724
  // in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
25398
25725
  // missed and every captain ping reported accepted-unconfirmed.
25399
25726
  statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
25400
- wire: (p, e) => writeLine(p, e, { connect: (path45) => netConnect2(path45) }),
25727
+ wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect2(path46) }),
25401
25728
  receipts,
25402
25729
  newMsgId: () => randomUUID7(),
25403
25730
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
@@ -25530,8 +25857,8 @@ var cmuxCommand = new Command28("cmux").description("cmux integration helpers").
25530
25857
  // packages/cli/src/commands/effort.ts
25531
25858
  init_dist();
25532
25859
  init_dist2();
25533
- import fs34 from "fs";
25534
- import path36 from "path";
25860
+ import fs35 from "fs";
25861
+ import path37 from "path";
25535
25862
  import { Command as Command29 } from "commander";
25536
25863
  import chalk30 from "chalk";
25537
25864
  var VALID_EFFORTS = ["max", "balance", "low"];
@@ -25574,9 +25901,9 @@ function effortScopeLabel(projectName) {
25574
25901
  }
25575
25902
  function canonical(p) {
25576
25903
  try {
25577
- return fs34.realpathSync(p);
25904
+ return fs35.realpathSync(p);
25578
25905
  } catch {
25579
- return path36.resolve(p);
25906
+ return path37.resolve(p);
25580
25907
  }
25581
25908
  }
25582
25909
  async function notifyCaptainsOfEffort(effort, config, driver, cwd = process.cwd(), append, scopeProject, projectConfigRoot) {
@@ -25626,7 +25953,7 @@ var effortCommand = new Command29("effort").description("Get or set the crew tok
25626
25953
  const config = loadConfig();
25627
25954
  const registry = new RuntimeRegistry2({ cmux: createCmuxDriver2() });
25628
25955
  const driver = registry.global(config);
25629
- const stateRoot = path36.join(path36.dirname(DEFAULT_CONFIG_PATH), "state");
25956
+ const stateRoot = path37.join(path37.dirname(DEFAULT_CONFIG_PATH), "state");
25630
25957
  const append = (project, text) => appendCaptainMessage({ stateRoot, project, text, source: "daemon" });
25631
25958
  await notifyCaptainsOfEffort(effort, config, driver, process.cwd(), append, options.project);
25632
25959
  } catch {
@@ -25636,19 +25963,19 @@ var effortCommand = new Command29("effort").description("Get or set the crew tok
25636
25963
 
25637
25964
  // packages/cli/src/commands/tokens.ts
25638
25965
  init_dist();
25639
- import fs35 from "fs";
25640
- import path37 from "path";
25641
- import os19 from "os";
25966
+ import fs36 from "fs";
25967
+ import path38 from "path";
25968
+ import os20 from "os";
25642
25969
  import readline3 from "readline";
25643
25970
  import { Command as Command30 } from "commander";
25644
25971
  import chalk31 from "chalk";
25645
- var CLAUDE_PROJECTS_DIR = path37.join(os19.homedir(), ".claude", "projects");
25972
+ var CLAUDE_PROJECTS_DIR = path38.join(os20.homedir(), ".claude", "projects");
25646
25973
  function parseTranscriptLine(rawLine) {
25647
- const line = rawLine.trim();
25648
- if (!line) return { timestamp: null, usage: null };
25974
+ const line2 = rawLine.trim();
25975
+ if (!line2) return { timestamp: null, usage: null };
25649
25976
  let obj;
25650
25977
  try {
25651
- obj = JSON.parse(line);
25978
+ obj = JSON.parse(line2);
25652
25979
  } catch {
25653
25980
  return { timestamp: null, usage: null };
25654
25981
  }
@@ -25692,9 +26019,9 @@ function foldTranscriptLine(agg, rawLine, state) {
25692
26019
  async function aggregateTranscriptFile(filePath) {
25693
26020
  const agg = emptySessionAggregate();
25694
26021
  const state = { lastCacheRead: null };
25695
- const rl = readline3.createInterface({ input: fs35.createReadStream(filePath), crlfDelay: Infinity });
25696
- for await (const line of rl) {
25697
- foldTranscriptLine(agg, line, state);
26022
+ const rl = readline3.createInterface({ input: fs36.createReadStream(filePath), crlfDelay: Infinity });
26023
+ for await (const line2 of rl) {
26024
+ foldTranscriptLine(agg, line2, state);
25698
26025
  }
25699
26026
  return agg;
25700
26027
  }
@@ -25760,22 +26087,22 @@ function buildRoleReport(role, sessions) {
25760
26087
  }
25761
26088
  async function readdirSafe(dir) {
25762
26089
  try {
25763
- return await fs35.promises.readdir(dir);
26090
+ return await fs36.promises.readdir(dir);
25764
26091
  } catch {
25765
26092
  return [];
25766
26093
  }
25767
26094
  }
25768
26095
  async function listJsonlFiles(dir) {
25769
26096
  const entries = await readdirSafe(dir);
25770
- return entries.filter((e) => e.endsWith(".jsonl")).map((e) => path37.join(dir, e));
26097
+ return entries.filter((e) => e.endsWith(".jsonl")).map((e) => path38.join(dir, e));
25771
26098
  }
25772
26099
  async function findTranscriptDirs(claudeProjectsDir, captainSlug) {
25773
26100
  const entries = await readdirSafe(claudeProjectsDir);
25774
26101
  const captainDirs = [];
25775
26102
  const crewDirs = [];
25776
26103
  for (const entry of entries) {
25777
- if (entry === captainSlug) captainDirs.push(path37.join(claudeProjectsDir, entry));
25778
- else if (isCrewDirName(entry, captainSlug)) crewDirs.push(path37.join(claudeProjectsDir, entry));
26104
+ if (entry === captainSlug) captainDirs.push(path38.join(claudeProjectsDir, entry));
26105
+ else if (isCrewDirName(entry, captainSlug)) crewDirs.push(path38.join(claudeProjectsDir, entry));
25779
26106
  }
25780
26107
  return { captainDirs, crewDirs };
25781
26108
  }
@@ -26233,7 +26560,7 @@ telegramCommand.command("send").argument("<project>", "project whose topic recei
26233
26560
  const { createInterface: createInterface2 } = await import("readline");
26234
26561
  const lines = [];
26235
26562
  const rl = createInterface2({ input: process.stdin });
26236
- for await (const line of rl) lines.push(line);
26563
+ for await (const line2 of rl) lines.push(line2);
26237
26564
  message = lines.join("\n").trimEnd();
26238
26565
  if (!message) {
26239
26566
  console.error(chalk32.red("no message provided (stdin was empty)"));
@@ -26258,11 +26585,12 @@ init_dist2();
26258
26585
  init_dist3();
26259
26586
  init_dist();
26260
26587
  import { Command as Command33 } from "commander";
26588
+ import { join as join36 } from "path";
26261
26589
  import { homedir as homedir20 } from "os";
26262
26590
 
26263
26591
  // packages/cli/src/lib/captain-session-registry.ts
26264
- import fs36 from "fs";
26265
- import path38 from "path";
26592
+ import fs37 from "fs";
26593
+ import path39 from "path";
26266
26594
 
26267
26595
  // packages/cli/src/lib/handoff-facts.ts
26268
26596
  var STALE_FETCH_WARNING_MS = 24 * 60 * 60 * 1e3;
@@ -26313,18 +26641,18 @@ function assembleHandoffFacts(live, claudeMem, gapSessions, checkpoint, now, ext
26313
26641
  // packages/cli/src/lib/captain-session-registry.ts
26314
26642
  var CAPTAIN_SESSION_REGISTRY_FILE = "captain-sessions.jsonl";
26315
26643
  function appendCaptainSession(spokeVault, record) {
26316
- fs36.mkdirSync(spokeVault, { recursive: true });
26317
- const file = path38.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
26318
- fs36.appendFileSync(file, JSON.stringify(record) + "\n");
26644
+ fs37.mkdirSync(spokeVault, { recursive: true });
26645
+ const file = path39.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
26646
+ fs37.appendFileSync(file, JSON.stringify(record) + "\n");
26319
26647
  }
26320
26648
  function readCaptainSessionRegistry(spokeVault) {
26321
- const file = path38.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
26322
- if (!fs36.existsSync(file)) return [];
26649
+ const file = path39.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
26650
+ if (!fs37.existsSync(file)) return [];
26323
26651
  const records = [];
26324
- for (const line of fs36.readFileSync(file, "utf-8").split("\n")) {
26325
- if (!line.trim()) continue;
26652
+ for (const line2 of fs37.readFileSync(file, "utf-8").split("\n")) {
26653
+ if (!line2.trim()) continue;
26326
26654
  try {
26327
- records.push(JSON.parse(line));
26655
+ records.push(JSON.parse(line2));
26328
26656
  } catch {
26329
26657
  }
26330
26658
  }
@@ -26636,9 +26964,25 @@ function recordCaptainSessionStart(payload) {
26636
26964
  } catch {
26637
26965
  }
26638
26966
  }
26967
+ var RULES_HOOK_EVENTS = { "session-start": "SessionStart", "prompt-submit": "UserPromptSubmit" };
26968
+ async function rulesHookOutput(sub, payload, opts) {
26969
+ if (sub !== "session-start" && sub !== "prompt-submit") return "";
26970
+ if (opts.env.SQUADRANT_RULES_INJECT === "0") return "";
26971
+ const ctx = await withBudget(() => computeRulesInjection({
26972
+ event: sub,
26973
+ payload,
26974
+ env: opts.env,
26975
+ cwd: opts.cwd,
26976
+ project: opts.project,
26977
+ cfg: (opts.loadCfg ?? loadConfig)(),
26978
+ stateRoot: opts.stateRoot ?? join36(CONFIG_DIR, "state")
26979
+ }), opts.budgetMs ?? INJECT_BUDGET_MS);
26980
+ if (!ctx) return "";
26981
+ return JSON.stringify({ hookSpecificOutput: { hookEventName: RULES_HOOK_EVENTS[sub], additionalContext: ctx } });
26982
+ }
26639
26983
  function hooksCommand() {
26640
26984
  const hooks = new Command33("hooks").description("(internal) receive lifecycle hook events from agent processes");
26641
- hooks.command("claude <sub>", { hidden: true }).description("internal: bridge a NativeHookSource claude hook to squadrantd").action(async (sub) => {
26985
+ hooks.command("claude <sub>", { hidden: true }).description("internal: bridge a NativeHookSource claude hook to squadrantd").option("--project <name>", "project for rules injection (default: SQUADRANT_CREW_PROJECT, then cwd)").action(async (sub, opts) => {
26642
26986
  let stdin = "";
26643
26987
  try {
26644
26988
  for await (const chunk of process.stdin) stdin += chunk;
@@ -26651,6 +26995,8 @@ function hooksCommand() {
26651
26995
  } catch {
26652
26996
  }
26653
26997
  }
26998
+ const rulesOut = await rulesHookOutput(sub, payload, { env: process.env, cwd: process.cwd(), project: opts.project });
26999
+ if (rulesOut) await new Promise((resolve4) => process.stdout.write(rulesOut, () => resolve4()));
26654
27000
  if (sub === "session-start" && process.env.SQUADRANT_ROLE === "captain") {
26655
27001
  recordCaptainSessionStart(payload);
26656
27002
  }
@@ -26707,13 +27053,13 @@ function hooksCommand() {
26707
27053
  // packages/cli/src/commands/work.ts
26708
27054
  init_dist();
26709
27055
  init_dist2();
26710
- import path39 from "path";
27056
+ import path40 from "path";
26711
27057
  import { Command as Command34 } from "commander";
26712
27058
  import chalk34 from "chalk";
26713
27059
  function detectCurrentProject(config, cwd = process.cwd()) {
26714
27060
  for (const [name, proj] of Object.entries(config.projects)) {
26715
27061
  const projPath = resolveHome(proj.path);
26716
- if (cwd === projPath || cwd.startsWith(projPath + path39.sep)) return name;
27062
+ if (cwd === projPath || cwd.startsWith(projPath + path40.sep)) return name;
26717
27063
  }
26718
27064
  return void 0;
26719
27065
  }
@@ -26762,8 +27108,8 @@ function stateColor(state) {
26762
27108
  }
26763
27109
  function printItem(item, indent) {
26764
27110
  const color = stateColor(item.state);
26765
- const line = " ".repeat(indent) + `${chalk34.dim(item.id)} ${item.title} ${color(`[${item.state}]`)}` + (indent === 0 ? chalk34.dim(` (${item.project})`) : "");
26766
- console.log(TERMINAL_WORK_STATES.has(item.state) ? chalk34.dim(line) : line);
27111
+ const line2 = " ".repeat(indent) + `${chalk34.dim(item.id)} ${item.title} ${color(`[${item.state}]`)}` + (indent === 0 ? chalk34.dim(` (${item.project})`) : "");
27112
+ console.log(TERMINAL_WORK_STATES.has(item.state) ? chalk34.dim(line2) : line2);
26767
27113
  }
26768
27114
  function printTree(items) {
26769
27115
  const { roots, childrenOf } = groupByParent(items);
@@ -26845,14 +27191,14 @@ var workCommand = new Command34("work").description("Track your own in-flight wo
26845
27191
  // packages/cli/src/commands/handoff.ts
26846
27192
  init_dist();
26847
27193
  import { Command as Command35 } from "commander";
26848
- import path42 from "path";
26849
- import os20 from "os";
27194
+ import path43 from "path";
27195
+ import os21 from "os";
26850
27196
 
26851
27197
  // packages/cli/src/lib/handoff-live-repo.ts
26852
27198
  init_dist();
26853
27199
  import { execFileSync as execFileSync13 } from "child_process";
26854
- import fs37 from "fs";
26855
- import path40 from "path";
27200
+ import fs38 from "fs";
27201
+ import path41 from "path";
26856
27202
 
26857
27203
  // packages/cli/src/lib/handoff-branch-state.ts
26858
27204
  function tryRun(runner, cmd, args, cwd) {
@@ -26991,7 +27337,7 @@ function localAheadOfBase(runner, projectPath, base) {
26991
27337
  }
26992
27338
  function readFetchAgeMs(projectPath, now) {
26993
27339
  try {
26994
- const stat2 = fs37.statSync(path40.join(projectPath, ".git", "FETCH_HEAD"));
27340
+ const stat2 = fs38.statSync(path41.join(projectPath, ".git", "FETCH_HEAD"));
26995
27341
  return Math.max(0, now - stat2.mtime.getTime());
26996
27342
  } catch {
26997
27343
  return null;
@@ -27062,7 +27408,7 @@ function gatherLiveRepoState(projectPath, fallbackBaseBranch, tasks, runner = de
27062
27408
 
27063
27409
  // packages/cli/src/lib/handoff-claude-mem.ts
27064
27410
  import { createRequire } from "module";
27065
- import fs38 from "fs";
27411
+ import fs39 from "fs";
27066
27412
  var { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
27067
27413
  var CLAUDE_MEM_RECENCY_LIMIT = 20;
27068
27414
  function decisionText(row) {
@@ -27076,7 +27422,7 @@ function decisionText(row) {
27076
27422
  return row.narrative ?? "";
27077
27423
  }
27078
27424
  function queryClaudeMem(dbPath, project) {
27079
- if (!fs38.existsSync(dbPath)) return null;
27425
+ if (!fs39.existsSync(dbPath)) return null;
27080
27426
  let db;
27081
27427
  try {
27082
27428
  db = new DatabaseSync(dbPath, { readOnly: true });
@@ -27119,7 +27465,7 @@ function queryClaudeMem(dbPath, project) {
27119
27465
  }
27120
27466
 
27121
27467
  // packages/cli/src/lib/handoff-transcript.ts
27122
- import fs39 from "fs";
27468
+ import fs40 from "fs";
27123
27469
  var TRANSCRIPT_BYTE_CAP = 2e5;
27124
27470
  var DIGEST_BYTE_CAP = 8 * 1024;
27125
27471
  var PROMPT_TRUNCATE_CHARS = 300;
@@ -27182,11 +27528,11 @@ function extractMessages(tailText) {
27182
27528
  const collectRefs = (text) => {
27183
27529
  for (const ref of findRefs(text)) refs.add(ref);
27184
27530
  };
27185
- for (const line of tailText.split("\n")) {
27186
- if (!line.trim()) continue;
27531
+ for (const line2 of tailText.split("\n")) {
27532
+ if (!line2.trim()) continue;
27187
27533
  let obj;
27188
27534
  try {
27189
- obj = JSON.parse(line);
27535
+ obj = JSON.parse(line2);
27190
27536
  } catch {
27191
27537
  continue;
27192
27538
  }
@@ -27228,27 +27574,27 @@ function extractMessages(tailText) {
27228
27574
  return { lastUserMessage, lastAssistantText, digest };
27229
27575
  }
27230
27576
  function extractTranscriptTail(transcriptPath, byteCap = TRANSCRIPT_BYTE_CAP) {
27231
- if (!fs39.existsSync(transcriptPath)) return null;
27232
- const content = fs39.readFileSync(transcriptPath, "utf-8");
27577
+ if (!fs40.existsSync(transcriptPath)) return null;
27578
+ const content = fs40.readFileSync(transcriptPath, "utf-8");
27233
27579
  const { lastUserMessage, lastAssistantText, digest } = extractMessages(tailOf(content, byteCap));
27234
- const mtimeIso = fs39.statSync(transcriptPath).mtime.toISOString();
27580
+ const mtimeIso = fs40.statSync(transcriptPath).mtime.toISOString();
27235
27581
  return { path: transcriptPath, mtimeIso, lastUserMessage, lastAssistantText, digest };
27236
27582
  }
27237
27583
 
27238
27584
  // packages/cli/src/lib/handoff-archive.ts
27239
- import fs40 from "fs";
27240
- import path41 from "path";
27585
+ import fs41 from "fs";
27586
+ import path42 from "path";
27241
27587
  function readNewestArchivedHandoff(spokeVault, now) {
27242
- const dir = path41.join(spokeVault, "handoffs");
27243
- if (!fs40.existsSync(dir)) return null;
27244
- const candidates = fs40.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
27245
- const full = path41.join(dir, e.name);
27246
- return { name: e.name, full, mtime: fs40.statSync(full).mtime };
27588
+ const dir = path42.join(spokeVault, "handoffs");
27589
+ if (!fs41.existsSync(dir)) return null;
27590
+ const candidates = fs41.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
27591
+ const full = path42.join(dir, e.name);
27592
+ return { name: e.name, full, mtime: fs41.statSync(full).mtime };
27247
27593
  }).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
27248
27594
  for (const candidate of candidates) {
27249
27595
  let content;
27250
27596
  try {
27251
- content = JSON.parse(fs40.readFileSync(candidate.full, "utf-8"));
27597
+ content = JSON.parse(fs41.readFileSync(candidate.full, "utf-8"));
27252
27598
  } catch {
27253
27599
  continue;
27254
27600
  }
@@ -27258,7 +27604,7 @@ function readNewestArchivedHandoff(spokeVault, now) {
27258
27604
  }
27259
27605
 
27260
27606
  // packages/cli/src/commands/handoff.ts
27261
- var CLAUDE_MEM_DB_PATH = path42.join(os20.homedir(), ".claude-mem", "claude-mem.db");
27607
+ var CLAUDE_MEM_DB_PATH = path43.join(os21.homedir(), ".claude-mem", "claude-mem.db");
27262
27608
  async function defaultFetchTasks(project) {
27263
27609
  return await squadrantdCall({ kind: "list", project });
27264
27610
  }
@@ -27326,9 +27672,9 @@ function filterSessions(rows, f) {
27326
27672
  if (f.agent && r.agent !== f.agent) return false;
27327
27673
  if (f.liveOnly && r.status === "stale") return false;
27328
27674
  if (f.project) {
27329
- const path45 = f.projects?.[f.project];
27675
+ const path46 = f.projects?.[f.project];
27330
27676
  const byRecord = r.project === f.project;
27331
- const byCwd = !!path45 && !!r.cwd && (r.cwd === normalized(path45) || r.cwd.startsWith(normalized(path45) + "/"));
27677
+ const byCwd = !!path46 && !!r.cwd && (r.cwd === normalized(path46) || r.cwd.startsWith(normalized(path46) + "/"));
27332
27678
  if (!byRecord && !byCwd) return false;
27333
27679
  }
27334
27680
  return true;
@@ -27348,8 +27694,8 @@ function formatSessionTable(rows) {
27348
27694
  ]);
27349
27695
  const all = [header, ...body];
27350
27696
  const widths = header.map((_, i) => Math.max(...all.map((row) => row[i].length)));
27351
- const line = (row) => row.map((c, i) => c.padEnd(widths[i])).join(" ").trimEnd();
27352
- return [line(header), ...body.map(line)].join("\n");
27697
+ const line2 = (row) => row.map((c, i) => c.padEnd(widths[i])).join(" ").trimEnd();
27698
+ return [line2(header), ...body.map(line2)].join("\n");
27353
27699
  }
27354
27700
  async function collectSessions(drivers) {
27355
27701
  const rows = [];
@@ -27418,8 +27764,8 @@ var sessionsCommand = new Command36("sessions").description("List live agent ses
27418
27764
  init_dist();
27419
27765
  init_dist2();
27420
27766
  init_dist3();
27421
- import os21 from "os";
27422
- import path43 from "path";
27767
+ import os22 from "os";
27768
+ import path44 from "path";
27423
27769
  import { Command as Command37 } from "commander";
27424
27770
  import chalk36 from "chalk";
27425
27771
 
@@ -27537,7 +27883,7 @@ function buildWhoamiDeps(opts = {}) {
27537
27883
  const projects = Object.fromEntries(
27538
27884
  Object.entries(config.projects).map(([n, p]) => [n, resolveHome(p.path)])
27539
27885
  );
27540
- const root = stateRoot ?? path43.join(os21.homedir(), ".config", "squadrant", "state");
27886
+ const root = stateRoot ?? path44.join(os22.homedir(), ".config", "squadrant", "state");
27541
27887
  const store = createStore(root);
27542
27888
  const merged = {
27543
27889
  env: process.env,
@@ -27589,8 +27935,8 @@ var whoamiCommand = new Command37("whoami").description("Show the agent session
27589
27935
  // packages/cli/src/commands/knowledge.ts
27590
27936
  init_dist();
27591
27937
  init_dist2();
27592
- import fs41 from "fs";
27593
- import path44 from "path";
27938
+ import fs42 from "fs";
27939
+ import path45 from "path";
27594
27940
  import { Command as Command38 } from "commander";
27595
27941
  import chalk37 from "chalk";
27596
27942
  var KNOWLEDGE_PRIVACY_NOTICE = "Sources are sent to the extraction crew's model; mark `sensitivity: local-only` to keep a source on local models only.";
@@ -27603,18 +27949,18 @@ function runKnowledgeInit(kb, configPath = DEFAULT_CONFIG_PATH) {
27603
27949
  const hub = resolveHome(cfg.hubVault);
27604
27950
  const dir = kbDir(hub, kb);
27605
27951
  const created = [];
27606
- for (const d of [path44.join(dir, "raw"), kbRulesDir(hub, kb), path44.join(kbRulesDir(hub, kb), PROPOSED_DIR)]) {
27607
- if (!fs41.existsSync(d)) {
27608
- fs41.mkdirSync(d, { recursive: true });
27609
- created.push(path44.relative(dir, d));
27952
+ for (const d of [path45.join(dir, "raw"), kbRulesDir(hub, kb), path45.join(kbRulesDir(hub, kb), PROPOSED_DIR)]) {
27953
+ if (!fs42.existsSync(d)) {
27954
+ fs42.mkdirSync(d, { recursive: true });
27955
+ created.push(path45.relative(dir, d));
27610
27956
  }
27611
27957
  }
27612
- const sourcesFile = path44.join(dir, "sources.yaml");
27613
- if (!fs41.existsSync(sourcesFile)) {
27614
- fs41.writeFileSync(sourcesFile, SOURCES_TEMPLATE);
27958
+ const sourcesFile = path45.join(dir, "sources.yaml");
27959
+ if (!fs42.existsSync(sourcesFile)) {
27960
+ fs42.writeFileSync(sourcesFile, SOURCES_TEMPLATE);
27615
27961
  created.push("sources.yaml");
27616
27962
  }
27617
- if (!fs41.existsSync(path44.join(dir, "index.json"))) {
27963
+ if (!fs42.existsSync(path45.join(dir, "index.json"))) {
27618
27964
  writeIndex(hub, kb, compileIndex(kb, []));
27619
27965
  created.push("index.json");
27620
27966
  }
@@ -27629,7 +27975,7 @@ function runKnowledgeSubscribe(kb, project, configPath = DEFAULT_CONFIG_PATH) {
27629
27975
  const cfg = loadConfig(configPath);
27630
27976
  const pc = cfg.projects[project];
27631
27977
  if (!pc) throw new Error(`Unknown project '${project}'`);
27632
- if (!fs41.existsSync(kbDir(resolveHome(cfg.hubVault), kb))) {
27978
+ if (!fs42.existsSync(kbDir(resolveHome(cfg.hubVault), kb))) {
27633
27979
  throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
27634
27980
  }
27635
27981
  const list = pc.knowledge ?? [];
@@ -27667,14 +28013,34 @@ function runKnowledgeReindex(kb, configPath = DEFAULT_CONFIG_PATH) {
27667
28013
  assertKbName(kb);
27668
28014
  const cfg = loadConfig(configPath);
27669
28015
  const hub = resolveHome(cfg.hubVault);
27670
- if (!fs41.existsSync(kbDir(hub, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
27671
- const { rules, errors } = loadKbRules(cfg, kb);
27672
- const file = writeIndex(hub, kb, compileIndex(kb, rules));
27673
- return { file, count: rules.length, errors: errors.length };
28016
+ if (!fs42.existsSync(kbDir(hub, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
28017
+ const { rules: all, errors } = loadKbRules(cfg, kb, { includeProposed: true });
28018
+ const proposedRoot = path45.join(kbRulesDir(hub, kb), PROPOSED_DIR) + path45.sep;
28019
+ const live = all.filter((r) => !r.file.startsWith(proposedRoot));
28020
+ const file = writeIndex(hub, kb, compileIndex(kb, live));
28021
+ return { file, count: live.length, proposed: all.length - live.length, errors: errors.length, invalid: errors };
28022
+ }
28023
+ function runKnowledgeValidate(kb, configPath = DEFAULT_CONFIG_PATH) {
28024
+ assertKbName(kb);
28025
+ const cfg = loadConfig(configPath);
28026
+ const hub = resolveHome(cfg.hubVault);
28027
+ if (!fs42.existsSync(kbDir(hub, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
28028
+ const { sources, errors } = loadSources(hub, kb);
28029
+ const res = validateKb({ rulesDir: kbRulesDir(hub, kb), kbRoot: kbDir(hub, kb), sources, domains: cfg.knowledge?.[kb]?.domains });
28030
+ const srcChecks = errors.map((e) => ({ level: "fail", message: `sources.yaml: ${e}` }));
28031
+ return { checks: [...srcChecks, ...res.checks], ok: res.ok && !errors.length };
27674
28032
  }
27675
28033
  knowledgeCommand.command("reindex <kb>").description("Recompile index.json from the KB's rule files").action((kb) => {
27676
28034
  const r = runKnowledgeReindex(kb);
27677
- console.log(`${r.file}: ${r.count} rules${r.errors ? chalk37.red(`, ${r.errors} invalid files skipped`) : ""}`);
28035
+ console.log(`${r.file}: ${r.count} active${r.proposed ? ` (+${r.proposed} proposed)` : ""}${r.errors ? chalk37.red(`, ${r.errors} invalid files skipped`) : ""}`);
28036
+ for (const e of r.invalid) console.log(chalk37.red(` \u2718 ${e.file}: ${e.problems.join("; ")}`));
28037
+ });
28038
+ knowledgeCommand.command("validate <kb>").description("CI-style check: invalid files, duplicate ids, quotes present in sources; exits non-zero on failure").action((kb) => {
28039
+ const { checks, ok: ok2 } = runKnowledgeValidate(kb);
28040
+ const mark2 = { ok: chalk37.green("\u2714"), fail: chalk37.red("\u2718"), warn: chalk37.yellow("!"), skip: chalk37.dim("-") };
28041
+ for (const c of checks) console.log(`${mark2[c.level]} ${c.message}`);
28042
+ console.log(ok2 ? chalk37.green("valid") : chalk37.red("invalid"));
28043
+ if (!ok2) process.exitCode = 1;
27678
28044
  });
27679
28045
 
27680
28046
  // packages/cli/src/commands/rules.ts
@@ -27682,6 +28048,7 @@ init_dist();
27682
28048
  init_dist2();
27683
28049
  import { Command as Command39 } from "commander";
27684
28050
  import chalk38 from "chalk";
28051
+ var DEFAULT_SEARCH_LIMIT = 5;
27685
28052
  function resolveRulesProject(cfg, opts) {
27686
28053
  const env = opts.env ?? process.env;
27687
28054
  const name = opts.project ?? env.SQUADRANT_CREW_PROJECT ?? detectCurrentProject(cfg, opts.cwd ?? process.cwd());
@@ -27697,6 +28064,32 @@ function formatRule(rule2) {
27697
28064
  ` source: ${src}`
27698
28065
  ].join("\n");
27699
28066
  }
28067
+ function formatBrief(rule2) {
28068
+ return `${rule2.modality.toUpperCase()} ${rule2.id}: ${rule2.statement}`;
28069
+ }
28070
+ function parseLimit(raw) {
28071
+ if (raw === void 0) return DEFAULT_SEARCH_LIMIT;
28072
+ const n = Number(raw);
28073
+ if (!Number.isInteger(n) || n < 1) throw new Error(`--limit must be a positive integer, got '${raw}'`);
28074
+ return n;
28075
+ }
28076
+ function renderSearch(hits, opts) {
28077
+ if (!hits.length) return ["(no matching rules)"];
28078
+ const limit = parseLimit(opts.limit);
28079
+ const shown = hits.slice(0, limit);
28080
+ const lines = shown.map((h) => opts.idsOnly ? h.rule.id : opts.brief ? `[${h.score}] ${formatBrief(h.rule)}` : `${formatRule(h.rule)}
28081
+ score: ${h.score}
28082
+ `);
28083
+ const more = hits.length - shown.length;
28084
+ if (more > 0) lines.push(`(+${more} more; use --limit)`);
28085
+ return lines;
28086
+ }
28087
+ function renderList2(rules, opts) {
28088
+ if (!rules.length) return ["(no rules)"];
28089
+ const sorted = [...rules].sort((a, b) => a.id.localeCompare(b.id));
28090
+ return sorted.map((r) => opts.brief ? formatBrief(r) : `${formatBrief(r)}
28091
+ ${r.status} \xB7 ${r.layer}`);
28092
+ }
27700
28093
  function loadFor(opts, configPath) {
27701
28094
  const cfg = loadConfig(configPath);
27702
28095
  const project = resolveRulesProject(cfg, opts);
@@ -27709,6 +28102,10 @@ function runRulesSearch(query, opts, configPath = DEFAULT_CONFIG_PATH) {
27709
28102
  const rules = loadFor(opts, configPath);
27710
28103
  return searchRules(rules, query, { statuses: opts.all ? [...RULE_STATUSES] : DEFAULT_SEARCH_STATUSES });
27711
28104
  }
28105
+ function runRulesList(opts, configPath = DEFAULT_CONFIG_PATH) {
28106
+ const statuses = opts.all ? RULE_STATUSES : DEFAULT_SEARCH_STATUSES;
28107
+ return loadFor(opts, configPath).filter((r) => statuses.includes(r.status));
28108
+ }
27712
28109
  function runRulesShow(id, opts, configPath = DEFAULT_CONFIG_PATH) {
27713
28110
  const rules = loadFor(opts, configPath);
27714
28111
  const statuses = opts.all ? RULE_STATUSES : DEFAULT_SEARCH_STATUSES;
@@ -27717,13 +28114,12 @@ function runRulesShow(id, opts, configPath = DEFAULT_CONFIG_PATH) {
27717
28114
  return rule2;
27718
28115
  }
27719
28116
  var rulesCommand = new Command39("rules").description("Look up rules from subscribed knowledge bases (#893)");
27720
- rulesCommand.command("search <query...>").description("Search rules by keyword").option("--project <name>", "project (default: from cwd or SQUADRANT_CREW_PROJECT)").option("--all", "include proposed and retired rules").action((query, opts) => {
28117
+ rulesCommand.command("search <query...>").description("Search rules by keyword (ranked; best match first)").option("--project <name>", "project (default: from cwd or SQUADRANT_CREW_PROJECT)").option("--all", "include proposed and retired rules").option("--limit <n>", `max results (default ${DEFAULT_SEARCH_LIMIT})`).option("--brief", "one line per rule: [score] MODALITY id: statement").option("--ids-only", "print only rule ids").action((query, opts) => {
27721
28118
  const hits = runRulesSearch(query.join(" "), opts);
27722
- if (!hits.length) {
27723
- console.log("(no matching rules)");
27724
- return;
27725
- }
27726
- for (const h of hits) console.log(formatRule(h.rule) + "\n");
28119
+ for (const line2 of renderSearch(hits, opts)) console.log(line2);
28120
+ });
28121
+ rulesCommand.command("list").description("List every resolved rule for the project").option("--project <name>", "project (default: from cwd or SQUADRANT_CREW_PROJECT)").option("--all", "include proposed and retired rules").option("--brief", "one line per rule: MODALITY id: statement").action((opts) => {
28122
+ for (const line2 of renderList2(runRulesList(opts), opts)) console.log(line2);
27727
28123
  });
27728
28124
  rulesCommand.command("show <ids...>").description("Show one or more rules in full").option("--project <name>", "project (default: from cwd or SQUADRANT_CREW_PROJECT)").option("--all", "include proposed and retired rules").action((ids, opts) => {
27729
28125
  for (const id of ids) {
@@ -27739,14 +28135,14 @@ init_dist();
27739
28135
  init_dist();
27740
28136
  init_dist();
27741
28137
  var __dirname = dirname12(fileURLToPath6(import.meta.url));
27742
- var pkg = JSON.parse(readFileSync21(join36(__dirname, "..", "package.json"), "utf-8"));
28138
+ var pkg = JSON.parse(readFileSync21(join37(__dirname, "..", "package.json"), "utf-8"));
27743
28139
  ensureRuntimeSynced({
27744
- sourceRoot: join36(__dirname, ".."),
27745
- runtimeRoot: join36(homedir21(), ".config", "squadrant")
28140
+ sourceRoot: join37(__dirname, ".."),
28141
+ runtimeRoot: join37(homedir21(), ".config", "squadrant")
27746
28142
  });
27747
28143
  if (!process.env.VITEST) {
27748
28144
  try {
27749
- syncShippedOpencodeSkills({ pkgRoot: join36(__dirname, "..") });
28145
+ syncShippedOpencodeSkills({ pkgRoot: join37(__dirname, "..") });
27750
28146
  } catch (err) {
27751
28147
  process.stderr.write(
27752
28148
  `squadrant: opencode skills sync skipped: ${err.message}
@@ -27756,7 +28152,7 @@ if (!process.env.VITEST) {
27756
28152
  }
27757
28153
  if (process.argv[2] !== "config") {
27758
28154
  try {
27759
- const cfgPath = join36(homedir21(), ".config", "squadrant", "config.json");
28155
+ const cfgPath = join37(homedir21(), ".config", "squadrant", "config.json");
27760
28156
  if (existsSync14(cfgPath)) {
27761
28157
  const cfg = JSON.parse(readConfigFileSync(cfgPath));
27762
28158
  if (needsCheck(cfg, pkg.version)) {