squadrant 0.26.1 → 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.
@@ -423,22 +423,22 @@ function defaultCmuxConfigPath() {
423
423
  return join(homedir(), ".config", "cmux", "cmux.json");
424
424
  }
425
425
  function ensureSocketAutomation(opts = {}) {
426
- const path28 = opts.path ?? defaultCmuxConfigPath();
427
- if (!existsSync(path28)) {
428
- mkdirSync(dirname(path28), { recursive: true });
429
- writeFileSync(path28, MINIMAL_TEMPLATE);
430
- return { path: path28, changed: true, alreadySet: false };
426
+ const path29 = opts.path ?? defaultCmuxConfigPath();
427
+ if (!existsSync(path29)) {
428
+ mkdirSync(dirname(path29), { recursive: true });
429
+ writeFileSync(path29, MINIMAL_TEMPLATE);
430
+ return { path: path29, changed: true, alreadySet: false };
431
431
  }
432
- const text = readFileSync(path28, "utf-8");
432
+ const text = readFileSync(path29, "utf-8");
433
433
  const current = parse(text)?.automation?.socketControlMode;
434
434
  if (current === AUTOMATION_MODE) {
435
- return { path: path28, changed: false, alreadySet: true };
435
+ return { path: path29, changed: false, alreadySet: true };
436
436
  }
437
437
  const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
438
438
  formattingOptions: { insertSpaces: true, tabSize: 2 }
439
439
  });
440
- writeFileSync(path28, applyEdits(text, edits));
441
- return { path: path28, changed: true, alreadySet: false };
440
+ writeFileSync(path29, applyEdits(text, edits));
441
+ return { path: path29, changed: true, alreadySet: false };
442
442
  }
443
443
  var SOCKET_CONTROL_MODE_PATH, AUTOMATION_MODE, MINIMAL_TEMPLATE;
444
444
  var init_cmux_config = __esm({
@@ -588,9 +588,9 @@ import { join as join4 } from "path";
588
588
  function defaultStatePath() {
589
589
  return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
590
590
  }
591
- function readState(path28) {
591
+ function readState(path29) {
592
592
  try {
593
- return JSON.parse(readConfigFileSync(path28));
593
+ return JSON.parse(readConfigFileSync(path29));
594
594
  } catch {
595
595
  return {};
596
596
  }
@@ -1774,12 +1774,12 @@ async function* readFromCursor(opts) {
1774
1774
  continue;
1775
1775
  throw e;
1776
1776
  }
1777
- for (const line of buf.split("\n")) {
1778
- if (!line.trim())
1777
+ for (const line2 of buf.split("\n")) {
1778
+ if (!line2.trim())
1779
1779
  continue;
1780
1780
  let entry;
1781
1781
  try {
1782
- entry = JSON.parse(line);
1782
+ entry = JSON.parse(line2);
1783
1783
  } catch {
1784
1784
  continue;
1785
1785
  }
@@ -1881,17 +1881,17 @@ function createDecoder(onParseError) {
1881
1881
  const out = [];
1882
1882
  let idx;
1883
1883
  while ((idx = buf.indexOf("\n")) >= 0) {
1884
- const line = buf.slice(0, idx);
1884
+ const line2 = buf.slice(0, idx);
1885
1885
  buf = buf.slice(idx + 1);
1886
- if (!line.trim())
1886
+ if (!line2.trim())
1887
1887
  continue;
1888
1888
  try {
1889
- const parsed = JSON.parse(line);
1889
+ const parsed = JSON.parse(line2);
1890
1890
  if (typeof parsed === "object" && parsed !== null && parsed.type === "_keepalive")
1891
1891
  continue;
1892
1892
  out.push(parsed);
1893
1893
  } catch {
1894
- onParseError?.(line);
1894
+ onParseError?.(line2);
1895
1895
  }
1896
1896
  }
1897
1897
  return out;
@@ -2051,11 +2051,11 @@ function encodeFrame(f) {
2051
2051
  }
2052
2052
  function decodeFrames(wire) {
2053
2053
  const out = [];
2054
- for (const line of wire.split("\n")) {
2055
- if (!line.trim())
2054
+ for (const line2 of wire.split("\n")) {
2055
+ if (!line2.trim())
2056
2056
  continue;
2057
2057
  try {
2058
- const parsed = JSON.parse(line);
2058
+ const parsed = JSON.parse(line2);
2059
2059
  if (parsed.type === "_keepalive")
2060
2060
  continue;
2061
2061
  out.push(parsed);
@@ -2537,10 +2537,10 @@ function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
2537
2537
  isUpgrade: isVersionUpgrade(parsed.daemonEntry, thisEntry)
2538
2538
  };
2539
2539
  }
2540
- function sanitizePathForPlist(path28) {
2540
+ function sanitizePathForPlist(path29) {
2541
2541
  const seen = /* @__PURE__ */ new Set();
2542
2542
  const stable = [];
2543
- for (const p of path28.split(":")) {
2543
+ for (const p of path29.split(":")) {
2544
2544
  if (!p)
2545
2545
  continue;
2546
2546
  if (p.includes("/.claude/plugins/"))
@@ -3243,14 +3243,14 @@ function detectTrailingQuestion(text) {
3243
3243
  let inFence = false;
3244
3244
  let lastLine = null;
3245
3245
  for (const raw of text.split(/\r?\n/)) {
3246
- const line = raw.trim();
3247
- if (line.startsWith("```")) {
3246
+ const line2 = raw.trim();
3247
+ if (line2.startsWith("```")) {
3248
3248
  inFence = !inFence;
3249
3249
  continue;
3250
3250
  }
3251
- if (inFence || line === "")
3251
+ if (inFence || line2 === "")
3252
3252
  continue;
3253
- lastLine = line;
3253
+ lastLine = line2;
3254
3254
  }
3255
3255
  if (lastLine && lastLine.endsWith("?"))
3256
3256
  return lastLine;
@@ -3261,9 +3261,9 @@ function isQuotedLine(raw) {
3261
3261
  return QUOTED_PREFIX_RE.test(noAnsi);
3262
3262
  }
3263
3263
  function stripChrome(raw) {
3264
- let line = raw.replace(/\[[0-9;]*m/g, "");
3265
- line = line.replace(/^[\s│┃▏▕|]+/, "").replace(/[\s│┃▏▕|]+$/, "");
3266
- const trimmed = line.trim();
3264
+ let line2 = raw.replace(/\[[0-9;]*m/g, "");
3265
+ line2 = line2.replace(/^[\s│┃▏▕|]+/, "").replace(/[\s│┃▏▕|]+$/, "");
3266
+ const trimmed = line2.trim();
3267
3267
  if (trimmed === "")
3268
3268
  return null;
3269
3269
  if (PURE_CHROME_RE.test(trimmed))
@@ -3924,12 +3924,12 @@ function extractUserIntentFromTranscript(jsonl) {
3924
3924
  return null;
3925
3925
  const lines = jsonl.split(/\r?\n/);
3926
3926
  for (let i = lines.length - 1; i >= 0; i--) {
3927
- const line = lines[i].trim();
3928
- if (!line)
3927
+ const line2 = lines[i].trim();
3928
+ if (!line2)
3929
3929
  continue;
3930
3930
  let entry;
3931
3931
  try {
3932
- entry = JSON.parse(line);
3932
+ entry = JSON.parse(line2);
3933
3933
  } catch {
3934
3934
  continue;
3935
3935
  }
@@ -4378,10 +4378,10 @@ async function reapCrewChildren(taskId, graceMs = 2e3, execFn = nodeExec) {
4378
4378
  execFn("ps auxE", { maxBuffer: 64 * 1024 * 1024 }, (err, out) => err ? reject(err) : resolve4(out));
4379
4379
  });
4380
4380
  const pids = [];
4381
- for (const line of stdout.split("\n").slice(1)) {
4382
- if (!line.includes(marker))
4381
+ for (const line2 of stdout.split("\n").slice(1)) {
4382
+ if (!line2.includes(marker))
4383
4383
  continue;
4384
- const pid = parseInt(line.trim().split(/\s+/)[1], 10);
4384
+ const pid = parseInt(line2.trim().split(/\s+/)[1], 10);
4385
4385
  if (!isNaN(pid) && pid !== process.pid)
4386
4386
  pids.push(pid);
4387
4387
  }
@@ -5076,11 +5076,11 @@ var init_captain_record = __esm({
5076
5076
  // packages/core/dist/opencode-session.js
5077
5077
  import { execFileSync as execFileSync4 } from "child_process";
5078
5078
  async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
5079
- for (const path28 of ["/session", "/api/session"]) {
5079
+ for (const path29 of ["/session", "/api/session"]) {
5080
5080
  const ac = new AbortController();
5081
5081
  const t = setTimeout(() => ac.abort(), timeoutMs);
5082
5082
  try {
5083
- const res = await fetchImpl(`http://127.0.0.1:${port}${path28}`, { signal: ac.signal });
5083
+ const res = await fetchImpl(`http://127.0.0.1:${port}${path29}`, { signal: ac.signal });
5084
5084
  if (!res.ok)
5085
5085
  continue;
5086
5086
  const rows = await res.json();
@@ -5095,8 +5095,8 @@ async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
5095
5095
  }
5096
5096
  function parseLiveOpencodeServers(psOutput) {
5097
5097
  const out = [];
5098
- for (const line of psOutput.split("\n")) {
5099
- const m = line.match(/^\s*(\d+)\s+(.+)$/);
5098
+ for (const line2 of psOutput.split("\n")) {
5099
+ const m = line2.match(/^\s*(\d+)\s+(.+)$/);
5100
5100
  if (!m)
5101
5101
  continue;
5102
5102
  const pid = Number(m[1]);
@@ -5122,8 +5122,8 @@ function defaultPsOutput() {
5122
5122
  function defaultCwdOf(pid) {
5123
5123
  try {
5124
5124
  const out = execFileSync4("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], { encoding: "utf-8", timeout: 2e3 });
5125
- const line = out.split("\n").find((l) => l.startsWith("n"));
5126
- return line ? line.slice(1) : null;
5125
+ const line2 = out.split("\n").find((l) => l.startsWith("n"));
5126
+ return line2 ? line2.slice(1) : null;
5127
5127
  } catch {
5128
5128
  return null;
5129
5129
  }
@@ -5773,10 +5773,10 @@ function distBuiltAt() {
5773
5773
  return 0;
5774
5774
  }
5775
5775
  }
5776
- function gatherLogStats(path28, now, windowMs) {
5776
+ function gatherLogStats(path29, now, windowMs) {
5777
5777
  let sizeBytes = 0;
5778
5778
  try {
5779
- sizeBytes = statSync3(path28).size;
5779
+ sizeBytes = statSync3(path29).size;
5780
5780
  } catch {
5781
5781
  return { errorCount: 0, sizeBytes: 0, windowMs };
5782
5782
  }
@@ -5787,7 +5787,7 @@ function gatherLogStats(path28, now, windowMs) {
5787
5787
  const len = sizeBytes - start;
5788
5788
  let text = "";
5789
5789
  try {
5790
- const fd = openSync2(path28, "r");
5790
+ const fd = openSync2(path29, "r");
5791
5791
  try {
5792
5792
  const buf = Buffer.alloc(len);
5793
5793
  readSync(fd, buf, 0, len, start);
@@ -5800,10 +5800,10 @@ function gatherLogStats(path28, now, windowMs) {
5800
5800
  }
5801
5801
  const cutoff = now - windowMs;
5802
5802
  let errorCount = 0;
5803
- for (const line of text.split("\n")) {
5804
- if (!/error|failed/i.test(line))
5803
+ for (const line2 of text.split("\n")) {
5804
+ if (!/error|failed/i.test(line2))
5805
5805
  continue;
5806
- const m = line.match(/\d{4}-\d{2}-\d{2}T[\d:.]+Z/);
5806
+ const m = line2.match(/\d{4}-\d{2}-\d{2}T[\d:.]+Z/);
5807
5807
  if (m) {
5808
5808
  const ts = Date.parse(m[0]);
5809
5809
  if (!Number.isNaN(ts) && ts < cutoff)
@@ -7978,10 +7978,10 @@ function scan(bufRef, acc) {
7978
7978
  let saw = false;
7979
7979
  let idx;
7980
7980
  while ((idx = bufRef.value.indexOf("\n")) !== -1) {
7981
- const line = bufRef.value.slice(0, idx).trim();
7981
+ const line2 = bufRef.value.slice(0, idx).trim();
7982
7982
  bufRef.value = bufRef.value.slice(idx + 1);
7983
- if (line.startsWith("data:")) {
7984
- const payload = line.slice(5).trim();
7983
+ if (line2.startsWith("data:")) {
7984
+ const payload = line2.slice(5).trim();
7985
7985
  if (payload && payload !== "[DONE]") {
7986
7986
  try {
7987
7987
  if (absorb(JSON.parse(payload), acc))
@@ -8032,8 +8032,8 @@ var init_stream = __esm({
8032
8032
  // packages/core/dist/router/shim.js
8033
8033
  import { createServer as createServer3 } from "http";
8034
8034
  import { Readable } from "stream";
8035
- function joinUrl(base, path28) {
8036
- return base.replace(/\/+$/, "") + path28;
8035
+ function joinUrl(base, path29) {
8036
+ return base.replace(/\/+$/, "") + path29;
8037
8037
  }
8038
8038
  async function readBody(req) {
8039
8039
  const chunks = [];
@@ -8209,8 +8209,8 @@ function createRouterShim(opts) {
8209
8209
  writeJson(res, 200, { input_tokens: Math.max(1, Math.ceil(text.length / 4)) });
8210
8210
  }
8211
8211
  function handler(req, res) {
8212
- const path28 = pathnameOf(req.url);
8213
- if (req.method === "POST" && path28 === "/v1/messages") {
8212
+ const path29 = pathnameOf(req.url);
8213
+ if (req.method === "POST" && path29 === "/v1/messages") {
8214
8214
  void handleMessages(req, res).catch((err) => {
8215
8215
  log(`router internal error: ${err instanceof Error ? err.message : String(err)}`);
8216
8216
  if (!res.headersSent) {
@@ -8222,18 +8222,18 @@ function createRouterShim(opts) {
8222
8222
  });
8223
8223
  return;
8224
8224
  }
8225
- if (req.method === "POST" && path28 === "/v1/messages/count_tokens") {
8225
+ if (req.method === "POST" && path29 === "/v1/messages/count_tokens") {
8226
8226
  void handleCountTokens(req, res).catch(() => {
8227
8227
  if (!res.headersSent)
8228
8228
  writeJson(res, 502, anthropicError(502, "api_error", "router internal error").body);
8229
8229
  });
8230
8230
  return;
8231
8231
  }
8232
- if (req.method === "GET" && path28 === "/v1/models") {
8232
+ if (req.method === "GET" && path29 === "/v1/models") {
8233
8233
  writeJson(res, 200, modelsList([...advertisedModels]));
8234
8234
  return;
8235
8235
  }
8236
- if (req.method === "GET" && path28 === "/healthz") {
8236
+ if (req.method === "GET" && path29 === "/healthz") {
8237
8237
  writeJson(res, 200, { ready: server?.listening === true, upstreamReachable, lastError });
8238
8238
  return;
8239
8239
  }
@@ -8502,11 +8502,11 @@ async function probeCaptainChannel(project, opts = {}) {
8502
8502
  }
8503
8503
  }
8504
8504
  async function httpReachable(port, fetchImpl, timeoutMs) {
8505
- for (const path28 of ["/session", "/api/session"]) {
8505
+ for (const path29 of ["/session", "/api/session"]) {
8506
8506
  const ac = new AbortController();
8507
8507
  const t = setTimeout(() => ac.abort(), timeoutMs);
8508
8508
  try {
8509
- const res = await fetchImpl(`http://127.0.0.1:${port}${path28}`, { signal: ac.signal });
8509
+ const res = await fetchImpl(`http://127.0.0.1:${port}${path29}`, { signal: ac.signal });
8510
8510
  if (res.ok)
8511
8511
  return true;
8512
8512
  } catch {
@@ -9689,28 +9689,28 @@ function requireSnippet() {
9689
9689
  const maxLineLength = options.maxLength - (options.indent + lineNoLength + 3);
9690
9690
  for (let i = 1; i <= options.linesBefore; i++) {
9691
9691
  if (foundLineNo - i < 0) break;
9692
- const line2 = getLine(
9692
+ const line22 = getLine(
9693
9693
  mark2.buffer,
9694
9694
  lineStarts[foundLineNo - i],
9695
9695
  lineEnds[foundLineNo - i],
9696
9696
  mark2.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]),
9697
9697
  maxLineLength
9698
9698
  );
9699
- result = common2.repeat(" ", options.indent) + padStart((mark2.line - i + 1).toString(), lineNoLength) + " | " + line2.str + "\n" + result;
9699
+ result = common2.repeat(" ", options.indent) + padStart((mark2.line - i + 1).toString(), lineNoLength) + " | " + line22.str + "\n" + result;
9700
9700
  }
9701
- const line = getLine(mark2.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark2.position, maxLineLength);
9702
- result += common2.repeat(" ", options.indent) + padStart((mark2.line + 1).toString(), lineNoLength) + " | " + line.str + "\n";
9703
- result += common2.repeat("-", options.indent + lineNoLength + 3 + line.pos) + "^\n";
9701
+ const line2 = getLine(mark2.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark2.position, maxLineLength);
9702
+ result += common2.repeat(" ", options.indent) + padStart((mark2.line + 1).toString(), lineNoLength) + " | " + line2.str + "\n";
9703
+ result += common2.repeat("-", options.indent + lineNoLength + 3 + line2.pos) + "^\n";
9704
9704
  for (let i = 1; i <= options.linesAfter; i++) {
9705
9705
  if (foundLineNo + i >= lineEnds.length) break;
9706
- const line2 = getLine(
9706
+ const line22 = getLine(
9707
9707
  mark2.buffer,
9708
9708
  lineStarts[foundLineNo + i],
9709
9709
  lineEnds[foundLineNo + i],
9710
9710
  mark2.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]),
9711
9711
  maxLineLength
9712
9712
  );
9713
- result += common2.repeat(" ", options.indent) + padStart((mark2.line + i + 1).toString(), lineNoLength) + " | " + line2.str + "\n";
9713
+ result += common2.repeat(" ", options.indent) + padStart((mark2.line + i + 1).toString(), lineNoLength) + " | " + line22.str + "\n";
9714
9714
  }
9715
9715
  return result.replace(/\n$/, "");
9716
9716
  }
@@ -11997,17 +11997,17 @@ function requireDumper() {
11997
11997
  let result = "";
11998
11998
  const length = string.length;
11999
11999
  while (position < length) {
12000
- let line;
12000
+ let line2;
12001
12001
  const next = string.indexOf("\n", position);
12002
12002
  if (next === -1) {
12003
- line = string.slice(position);
12003
+ line2 = string.slice(position);
12004
12004
  position = length;
12005
12005
  } else {
12006
- line = string.slice(position, next + 1);
12006
+ line2 = string.slice(position, next + 1);
12007
12007
  position = next + 1;
12008
12008
  }
12009
- if (line.length && line !== "\n") result += ind;
12010
- result += line;
12009
+ if (line2.length && line2 !== "\n") result += ind;
12010
+ result += line2;
12011
12011
  }
12012
12012
  return result;
12013
12013
  }
@@ -12192,15 +12192,15 @@ function requireDumper() {
12192
12192
  let match;
12193
12193
  while (match = lineRe.exec(string)) {
12194
12194
  const prefix = match[1];
12195
- const line = match[2];
12196
- moreIndented = line[0] === " ";
12197
- result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width);
12195
+ const line2 = match[2];
12196
+ moreIndented = line2[0] === " ";
12197
+ result += prefix + (!prevMoreIndented && !moreIndented && line2 !== "" ? "\n" : "") + foldLine(line2, width);
12198
12198
  prevMoreIndented = moreIndented;
12199
12199
  }
12200
12200
  return result;
12201
12201
  }
12202
- function foldLine(line, width) {
12203
- if (line === "" || line[0] === " ") return line;
12202
+ function foldLine(line2, width) {
12203
+ if (line2 === "" || line2[0] === " ") return line2;
12204
12204
  const breakRe = / [^ ]/g;
12205
12205
  let match;
12206
12206
  let start = 0;
@@ -12208,20 +12208,20 @@ function requireDumper() {
12208
12208
  let curr = 0;
12209
12209
  let next = 0;
12210
12210
  let result = "";
12211
- while (match = breakRe.exec(line)) {
12211
+ while (match = breakRe.exec(line2)) {
12212
12212
  next = match.index;
12213
12213
  if (next - start > width) {
12214
12214
  end = curr > start ? curr : next;
12215
- result += "\n" + line.slice(start, end);
12215
+ result += "\n" + line2.slice(start, end);
12216
12216
  start = end + 1;
12217
12217
  }
12218
12218
  curr = next;
12219
12219
  }
12220
12220
  result += "\n";
12221
- if (line.length - start > width && curr > start) {
12222
- result += line.slice(start, curr) + "\n" + line.slice(curr + 1);
12221
+ if (line2.length - start > width && curr > start) {
12222
+ result += line2.slice(start, curr) + "\n" + line2.slice(curr + 1);
12223
12223
  } else {
12224
- result += line.slice(start);
12224
+ result += line2.slice(start);
12225
12225
  }
12226
12226
  return result.slice(1);
12227
12227
  }
@@ -12630,6 +12630,220 @@ var init_sources = __esm({
12630
12630
  }
12631
12631
  });
12632
12632
 
12633
+ // packages/core/dist/knowledge/inject.js
12634
+ import fs19 from "fs";
12635
+ import path18 from "path";
12636
+ function sessionOrder(a, b) {
12637
+ const proj = (r) => r.layer.startsWith("project:") ? 0 : 1;
12638
+ const mod = (r) => r.modality === "must-not" ? 0 : 1;
12639
+ return proj(a) - proj(b) || mod(a) - mod(b) || a.id.localeCompare(b.id);
12640
+ }
12641
+ function formatSessionContext(kbs, rules, cap = SESSION_RULE_CAP) {
12642
+ const hard = rules.filter((r) => r.status === "active" && (r.modality === "must" || r.modality === "must-not")).sort(sessionOrder);
12643
+ const shown = hard.slice(0, cap);
12644
+ const lines = [
12645
+ `<squadrant-project-rules kb="${kbs.join(",")}">`,
12646
+ `Rules KB: ${kbs.join(", ")}. ${DATA_NOTE}`,
12647
+ ...shown.map(line)
12648
+ ];
12649
+ if (hard.length > shown.length)
12650
+ lines.push(`+${hard.length - shown.length} more: squadrant rules list --brief`);
12651
+ lines.push("Look up rules for a task with `squadrant rules search <terms>` / `squadrant rules show <id>` (rules-ops skill).");
12652
+ lines.push("</squadrant-project-rules>");
12653
+ return { text: lines.join("\n"), ids: shown.map((r) => r.id) };
12654
+ }
12655
+ function cleanPromptQuery(prompt) {
12656
+ 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, " ");
12657
+ const terms = [];
12658
+ const add = (t) => {
12659
+ if (t.length < 3 && !SHORT_TERMS.has(t) || /^\d+$/.test(t) || STOPWORDS.has(t) || terms.includes(t))
12660
+ return;
12661
+ terms.push(t);
12662
+ };
12663
+ for (const raw of text.split(/[^a-z0-9._-]+/)) {
12664
+ const t = raw.replace(/^[._-]+|[._-]+$/g, "");
12665
+ if (STOPWORDS.has(t))
12666
+ continue;
12667
+ add(t);
12668
+ const parts = t.split(/[._-]+/);
12669
+ if (parts.length > 1 && parts.every((x) => x.length >= 3 && !PREFIXES.has(x)))
12670
+ parts.forEach(add);
12671
+ if (terms.length >= MAX_TERMS)
12672
+ break;
12673
+ }
12674
+ return terms.slice(0, MAX_TERMS).join(" ");
12675
+ }
12676
+ function wholeWordTerms(rule, terms) {
12677
+ const text = [
12678
+ rule.id,
12679
+ ...rule.triggers?.keywords ?? [],
12680
+ ...rule.triggers?.expanded ?? [],
12681
+ rule.triggers?.when ?? "",
12682
+ rule.statement
12683
+ ].join("\n").toLowerCase();
12684
+ return terms.filter((t) => {
12685
+ const base = t.length > 4 ? t.replace(/(es|s)$/, "") : t;
12686
+ return new RegExp(`(^|[^a-z0-9])(?:${escapeRe(t)}|${escapeRe(base)}(?:s|es)?)($|[^a-z0-9])`).test(text);
12687
+ });
12688
+ }
12689
+ function selectPromptHits(hits, query, seen, opts = {}) {
12690
+ const minScore = opts.minScore ?? PROMPT_MIN_SCORE;
12691
+ const terms = query.split(" ").filter(Boolean);
12692
+ return hits.filter((h) => {
12693
+ if (seen.has(h.rule.id))
12694
+ return false;
12695
+ const n = wholeWordTerms(h.rule, terms).length;
12696
+ return n >= 2 && h.score >= minScore || n === 1 && h.score >= PROMPT_SINGLE_TERM_MIN_SCORE;
12697
+ }).slice(0, opts.cap ?? PROMPT_RULE_CAP);
12698
+ }
12699
+ function isSystemPrompt(prompt) {
12700
+ const t = prompt.trimStart();
12701
+ return /^(⚠|🗒|\[stale\b|CREW [A-Z]|Another Claude session sent a message)/u.test(t) || t.includes("<cross-session-message");
12702
+ }
12703
+ function promptText(prompt) {
12704
+ const m = BRIEF_POINTER_RE.exec(prompt.trimStart());
12705
+ if (!m)
12706
+ return prompt;
12707
+ try {
12708
+ return fs19.readFileSync(m[1], "utf8").slice(0, MAX_PROMPT_CHARS * 2);
12709
+ } catch {
12710
+ return prompt;
12711
+ }
12712
+ }
12713
+ function formatPromptContext(hits) {
12714
+ return [
12715
+ '<squadrant-project-rules match="prompt">',
12716
+ `Rules that may apply to this prompt. ${DATA_NOTE}`,
12717
+ ...hits.map((h) => line(h.rule)),
12718
+ "</squadrant-project-rules>"
12719
+ ].join("\n");
12720
+ }
12721
+ function injectStateDir(stateRoot) {
12722
+ return path18.join(stateRoot, "rules-inject");
12723
+ }
12724
+ function readSeenRules(stateRoot, sessionId) {
12725
+ try {
12726
+ const ids = JSON.parse(fs19.readFileSync(sessionFile(stateRoot, sessionId), "utf8"));
12727
+ return new Set(Array.isArray(ids) ? ids.filter((x) => typeof x === "string") : []);
12728
+ } catch {
12729
+ return /* @__PURE__ */ new Set();
12730
+ }
12731
+ }
12732
+ function recordSeenRules(stateRoot, sessionId, ids) {
12733
+ if (!ids.length)
12734
+ return;
12735
+ const seen = readSeenRules(stateRoot, sessionId);
12736
+ for (const id of ids)
12737
+ seen.add(id);
12738
+ fs19.mkdirSync(injectStateDir(stateRoot), { recursive: true });
12739
+ fs19.writeFileSync(sessionFile(stateRoot, sessionId), JSON.stringify([...seen]));
12740
+ }
12741
+ function pruneSeenRules(stateRoot, now = Date.now()) {
12742
+ const dir = injectStateDir(stateRoot);
12743
+ let names;
12744
+ try {
12745
+ names = fs19.readdirSync(dir);
12746
+ } catch {
12747
+ return;
12748
+ }
12749
+ for (const n of names) {
12750
+ const f = path18.join(dir, n);
12751
+ try {
12752
+ if (now - fs19.statSync(f).mtimeMs > SEEN_TTL_MS)
12753
+ fs19.unlinkSync(f);
12754
+ } catch {
12755
+ }
12756
+ }
12757
+ }
12758
+ async function withBudget(fn, budgetMs = INJECT_BUDGET_MS) {
12759
+ const start = Date.now();
12760
+ let timer;
12761
+ try {
12762
+ const timeout = new Promise((resolve4) => {
12763
+ timer = setTimeout(() => resolve4(null), budgetMs);
12764
+ });
12765
+ const out = await Promise.race([Promise.resolve().then(fn), timeout]);
12766
+ return Date.now() - start > budgetMs ? null : out;
12767
+ } catch {
12768
+ return null;
12769
+ } finally {
12770
+ clearTimeout(timer);
12771
+ }
12772
+ }
12773
+ function resolveInjectProject(cfg, cwd, env, project) {
12774
+ const named = project ?? env.SQUADRANT_CREW_PROJECT;
12775
+ if (named)
12776
+ return cfg.projects[named] ? named : null;
12777
+ let best = null;
12778
+ let bestLen = -1;
12779
+ for (const [name, pc] of Object.entries(cfg.projects)) {
12780
+ const root = resolveHome(pc.path);
12781
+ if ((cwd === root || cwd.startsWith(root + path18.sep)) && root.length > bestLen) {
12782
+ best = name;
12783
+ bestLen = root.length;
12784
+ }
12785
+ }
12786
+ return best;
12787
+ }
12788
+ function computeRulesInjection(i) {
12789
+ if (i.env.SQUADRANT_RULES_INJECT === "0")
12790
+ return null;
12791
+ const p = typeof i.payload === "object" && i.payload !== null ? i.payload : {};
12792
+ const cwd = typeof p.cwd === "string" && p.cwd ? p.cwd : i.cwd;
12793
+ const project = resolveInjectProject(i.cfg, cwd, i.env, i.project);
12794
+ if (!project)
12795
+ return null;
12796
+ const kbs = subscribedKbs(i.cfg, project);
12797
+ if (!kbs.length)
12798
+ return null;
12799
+ const sessionId = typeof p.session_id === "string" && p.session_id ? p.session_id : null;
12800
+ if (i.event === "session-start") {
12801
+ const { text, ids } = formatSessionContext(kbs, resolveProjectRules(i.cfg, project).rules);
12802
+ if (sessionId) {
12803
+ pruneSeenRules(i.stateRoot);
12804
+ recordSeenRules(i.stateRoot, sessionId, ids);
12805
+ }
12806
+ return text;
12807
+ }
12808
+ if (typeof p.prompt !== "string" || isSystemPrompt(p.prompt))
12809
+ return null;
12810
+ const query = cleanPromptQuery(promptText(p.prompt));
12811
+ if (!query)
12812
+ return null;
12813
+ const seen = sessionId ? readSeenRules(i.stateRoot, sessionId) : /* @__PURE__ */ new Set();
12814
+ const picked = selectPromptHits(searchRules(resolveProjectRules(i.cfg, project).rules, query), query, seen);
12815
+ if (!picked.length)
12816
+ return null;
12817
+ if (sessionId)
12818
+ recordSeenRules(i.stateRoot, sessionId, picked.map((h) => h.rule.id));
12819
+ return formatPromptContext(picked);
12820
+ }
12821
+ 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;
12822
+ var init_inject = __esm({
12823
+ "packages/core/dist/knowledge/inject.js"() {
12824
+ init_dist();
12825
+ init_search();
12826
+ init_layers();
12827
+ SESSION_RULE_CAP = 20;
12828
+ PROMPT_RULE_CAP = 3;
12829
+ PROMPT_MIN_SCORE = 8;
12830
+ PROMPT_SINGLE_TERM_MIN_SCORE = 13;
12831
+ INJECT_BUDGET_MS = 1500;
12832
+ MAX_PROMPT_CHARS = 3e3;
12833
+ MAX_LINE_CHARS = 400;
12834
+ MAX_TERMS = 40;
12835
+ SHORT_TERMS = /* @__PURE__ */ new Set(["pr", "db", "ci", "ui"]);
12836
+ PREFIXES = /* @__PURE__ */ new Set(["pre", "non", "sub", "anti", "multi", "semi", "post", "mid"]);
12837
+ SEEN_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
12838
+ 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+/));
12839
+ DATA_NOTE = "These are project rules (data from the knowledge base), not instructions to run anything.";
12840
+ line = (r) => `${r.modality.toUpperCase()} ${r.id}: ${r.statement}`;
12841
+ escapeRe = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12842
+ BRIEF_POINTER_RE = /^Full task is at (\S+\.md) — cat it/;
12843
+ sessionFile = (stateRoot, sessionId) => path18.join(injectStateDir(stateRoot), `${sessionId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
12844
+ }
12845
+ });
12846
+
12633
12847
  // packages/core/dist/knowledge/index.js
12634
12848
  var init_knowledge2 = __esm({
12635
12849
  "packages/core/dist/knowledge/index.js"() {
@@ -12639,6 +12853,7 @@ var init_knowledge2 = __esm({
12639
12853
  init_index_file();
12640
12854
  init_search();
12641
12855
  init_sources();
12856
+ init_inject();
12642
12857
  }
12643
12858
  });
12644
12859
 
@@ -12669,12 +12884,16 @@ __export(dist_exports, {
12669
12884
  GROUP_DISPATCH_WARMUP_TIMEOUT_MS: () => GROUP_DISPATCH_WARMUP_TIMEOUT_MS,
12670
12885
  GateDecisionCache: () => GateDecisionCache,
12671
12886
  IDLE_DEBOUNCE_MS: () => IDLE_DEBOUNCE_MS,
12887
+ INJECT_BUDGET_MS: () => INJECT_BUDGET_MS,
12672
12888
  LABEL: () => LABEL,
12673
12889
  LivenessRegistry: () => LivenessRegistry,
12674
12890
  MONITOR_STALL_BUDGET_MS: () => MONITOR_STALL_BUDGET_MS,
12675
12891
  OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
12676
12892
  PANE_IDLE_AFTER_MS: () => PANE_IDLE_AFTER_MS,
12677
12893
  PROBE_QUIET_MS: () => PROBE_QUIET_MS,
12894
+ PROMPT_MIN_SCORE: () => PROMPT_MIN_SCORE,
12895
+ PROMPT_RULE_CAP: () => PROMPT_RULE_CAP,
12896
+ PROMPT_SINGLE_TERM_MIN_SCORE: () => PROMPT_SINGLE_TERM_MIN_SCORE,
12678
12897
  PROPOSED_DIR: () => PROPOSED_DIR,
12679
12898
  PROTOCOL_VERSION: () => PROTOCOL_VERSION,
12680
12899
  READ_ONLY_CREW_SUBCOMMANDS: () => READ_ONLY_CREW_SUBCOMMANDS,
@@ -12682,6 +12901,7 @@ __export(dist_exports, {
12682
12901
  ROUTER_READY_ATTEMPTS: () => ROUTER_READY_ATTEMPTS,
12683
12902
  ROUTER_READY_DELAY_MS: () => ROUTER_READY_DELAY_MS,
12684
12903
  SERVER_TOOL_TYPE_RE: () => SERVER_TOOL_TYPE_RE,
12904
+ SESSION_RULE_CAP: () => SESSION_RULE_CAP,
12685
12905
  SIDE_SESSION_ENV: () => SIDE_SESSION_ENV,
12686
12906
  SOURCES_TEMPLATE: () => SOURCES_TEMPLATE,
12687
12907
  STALE_THRESHOLD_MS: () => STALE_THRESHOLD_MS,
@@ -12722,9 +12942,11 @@ __export(dist_exports, {
12722
12942
  classifyCaptainPane: () => classifyCaptainPane,
12723
12943
  classifyHealth: () => classifyHealth,
12724
12944
  claudeEnvShadowsRouter: () => claudeEnvShadowsRouter,
12945
+ cleanPromptQuery: () => cleanPromptQuery,
12725
12946
  clearPending: () => clearPending,
12726
12947
  closeWorkItem: () => closeWorkItem,
12727
12948
  compileIndex: () => compileIndex,
12949
+ computeRulesInjection: () => computeRulesInjection,
12728
12950
  computeTemplateHash: () => computeTemplateHash,
12729
12951
  consumeExitMarker: () => consumeExitMarker,
12730
12952
  createAttach: () => createAttach,
@@ -12798,6 +13020,8 @@ __export(dist_exports, {
12798
13020
  formatLifecycle: () => formatLifecycle,
12799
13021
  formatMediaReceipt: () => formatMediaReceipt,
12800
13022
  formatPermissionDecision: () => formatPermissionDecision,
13023
+ formatPromptContext: () => formatPromptContext,
13024
+ formatSessionContext: () => formatSessionContext,
12801
13025
  formatUsageLine: () => formatUsageLine,
12802
13026
  formatWatchdogWarning: () => formatWatchdogWarning,
12803
13027
  freshTrace: () => freshTrace,
@@ -12807,6 +13031,7 @@ __export(dist_exports, {
12807
13031
  hasModalOptionList: () => hasModalOptionList,
12808
13032
  healCmdFor: () => healCmdFor,
12809
13033
  inboundBody: () => inboundBody,
13034
+ injectStateDir: () => injectStateDir,
12810
13035
  isAuthorized: () => isAuthorized,
12811
13036
  isBareSpawn: () => isBareSpawn,
12812
13037
  isCaptainAlive: () => isCaptainAlive,
@@ -12822,6 +13047,7 @@ __export(dist_exports, {
12822
13047
  isReadOnlyTopLevelCommand: () => isReadOnlyTopLevelCommand,
12823
13048
  isSideTitle: () => isSideTitle,
12824
13049
  isStickyAttention: () => isStickyAttention,
13050
+ isSystemPrompt: () => isSystemPrompt,
12825
13051
  isTurnAccepted: () => isTurnAccepted,
12826
13052
  isVersionUpgrade: () => isVersionUpgrade,
12827
13053
  joinUrl: () => joinUrl,
@@ -12867,6 +13093,7 @@ __export(dist_exports, {
12867
13093
  programArgsBlock: () => programArgsBlock,
12868
13094
  projectHealth: () => projectHealth,
12869
13095
  projectRulesDir: () => projectRulesDir,
13096
+ pruneSeenRules: () => pruneSeenRules,
12870
13097
  pruneTopics: () => pruneTopics,
12871
13098
  purgeExpiredWorkItems: () => purgeExpiredWorkItems,
12872
13099
  readCaptainAddress: () => readCaptainAddress,
@@ -12874,11 +13101,13 @@ __export(dist_exports, {
12874
13101
  readFromCursor: () => readFromCursor,
12875
13102
  readIndex: () => readIndex,
12876
13103
  readRunningMarker: () => readRunningMarker,
13104
+ readSeenRules: () => readSeenRules,
12877
13105
  readUserIntent: () => readUserIntent,
12878
13106
  realpathOrSelf: () => realpathOrSelf,
12879
13107
  reapCrewChildren: () => reapCrewChildren,
12880
13108
  reapOrphanedCrews: () => reapOrphanedCrews,
12881
13109
  reconcileLiveness: () => reconcileLiveness,
13110
+ recordSeenRules: () => recordSeenRules,
12882
13111
  recordSession: () => recordSession,
12883
13112
  recoverStall: () => recoverStall,
12884
13113
  reduce: () => reduce,
@@ -12900,6 +13129,7 @@ __export(dist_exports, {
12900
13129
  resolveGateMode: () => resolveGateMode,
12901
13130
  resolveGatePolicy: () => resolveGatePolicy,
12902
13131
  resolveGateTools: () => resolveGateTools,
13132
+ resolveInjectProject: () => resolveInjectProject,
12903
13133
  resolveProject: () => resolveProject,
12904
13134
  resolveProjectRules: () => resolveProjectRules,
12905
13135
  resolveRouterCredentials: () => resolveRouterCredentials,
@@ -12939,6 +13169,7 @@ __export(dist_exports, {
12939
13169
  screenHasSplashMarker: () => screenHasSplashMarker,
12940
13170
  screenHash: () => screenHash,
12941
13171
  searchRules: () => searchRules,
13172
+ selectPromptHits: () => selectPromptHits,
12942
13173
  sendRequest: () => sendRequest,
12943
13174
  setLastUserId: () => setLastUserId,
12944
13175
  setNotify: () => setNotify,
@@ -12967,6 +13198,8 @@ __export(dist_exports, {
12967
13198
  validateKb: () => validateKb,
12968
13199
  waitForCaptainDelivery: () => waitForCaptainDelivery,
12969
13200
  waitForWarmup: () => waitForWarmup,
13201
+ wholeWordTerms: () => wholeWordTerms,
13202
+ withBudget: () => withBudget,
12970
13203
  writeCaptainAddress: () => writeCaptainAddress,
12971
13204
  writeCursor: () => writeCursor,
12972
13205
  writeExitMarker: () => writeExitMarker,
@@ -13069,7 +13302,7 @@ import { readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs"
13069
13302
  import { join as join18 } from "path";
13070
13303
 
13071
13304
  // packages/agents/dist/claude/registry.js
13072
- import fs19 from "fs";
13305
+ import fs20 from "fs";
13073
13306
  import { join as join17 } from "path";
13074
13307
  import { homedir as homedir7 } from "os";
13075
13308
  var CLAUDE_SESSIONS_DIR = join17(homedir7(), ".claude", "sessions");
@@ -13114,11 +13347,11 @@ function toLifecycleSnapshot(entry, taskId, alive, now) {
13114
13347
  function readClaudeStatusBySocketPath(socketPath) {
13115
13348
  let files;
13116
13349
  try {
13117
- files = fs19.readdirSync(CLAUDE_SESSIONS_DIR);
13350
+ files = fs20.readdirSync(CLAUDE_SESSIONS_DIR);
13118
13351
  } catch {
13119
13352
  return void 0;
13120
13353
  }
13121
- const entries = parseRegistryDir(files, (name) => fs19.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
13354
+ const entries = parseRegistryDir(files, (name) => fs20.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
13122
13355
  const entry = entries.find((e) => e.messagingSocketPath === socketPath);
13123
13356
  if (!entry)
13124
13357
  return void 0;
@@ -13141,38 +13374,38 @@ import { homedir as homedir8 } from "os";
13141
13374
  var SQUADRANT_STATE_DIR = join19(homedir8(), ".config", "squadrant", "state");
13142
13375
 
13143
13376
  // packages/agents/dist/drivers/launch-cmd.js
13144
- import fs20 from "fs";
13145
- import path18 from "path";
13377
+ import fs21 from "fs";
13378
+ import path19 from "path";
13146
13379
 
13147
13380
  // packages/agents/dist/projection/cursor.js
13148
13381
  import { mkdir, readFile, writeFile } from "fs/promises";
13149
- import path19 from "path";
13382
+ import path20 from "path";
13150
13383
  import os8 from "os";
13151
13384
 
13152
13385
  // packages/agents/dist/projection/codex.js
13153
13386
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
13154
- import path20 from "path";
13387
+ import path21 from "path";
13155
13388
  import os9 from "os";
13156
13389
 
13157
13390
  // packages/agents/dist/projection/gemini.js
13158
13391
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
13159
- import path21 from "path";
13392
+ import path22 from "path";
13160
13393
  import os10 from "os";
13161
13394
 
13162
13395
  // packages/agents/dist/projection/opencode.js
13163
13396
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
13164
- import path22 from "path";
13397
+ import path23 from "path";
13165
13398
  import os11 from "os";
13166
13399
 
13167
13400
  // packages/agents/dist/projection/opencode-skills.js
13168
- import fs21 from "fs";
13401
+ import fs22 from "fs";
13169
13402
  import os12 from "os";
13170
- import path23 from "path";
13403
+ import path24 from "path";
13171
13404
  var OPENCODE_SKILL_MARKER = ".squadrant-managed";
13172
13405
  var MARKER_BODY = "squadrant\n";
13173
13406
  function defaultOpencodeSkillsRoot(env = process.env) {
13174
- const configHome = env.XDG_CONFIG_HOME || path23.join(os12.homedir(), ".config");
13175
- return path23.join(configHome, "opencode", "skills");
13407
+ const configHome = env.XDG_CONFIG_HOME || path24.join(os12.homedir(), ".config");
13408
+ return path24.join(configHome, "opencode", "skills");
13176
13409
  }
13177
13410
  var SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
13178
13411
  function parseSkillName(raw) {
@@ -13187,62 +13420,62 @@ function parseSkillName(raw) {
13187
13420
  }
13188
13421
  function listSourceSkills(sourceSkillsDir) {
13189
13422
  const out = /* @__PURE__ */ new Map();
13190
- if (!fs21.existsSync(sourceSkillsDir))
13423
+ if (!fs22.existsSync(sourceSkillsDir))
13191
13424
  return out;
13192
- for (const entry of fs21.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
13425
+ for (const entry of fs22.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
13193
13426
  if (!entry.isDirectory())
13194
13427
  continue;
13195
- const skillPath = path23.join(sourceSkillsDir, entry.name, "SKILL.md");
13196
- if (!fs21.existsSync(skillPath))
13428
+ const skillPath = path24.join(sourceSkillsDir, entry.name, "SKILL.md");
13429
+ if (!fs22.existsSync(skillPath))
13197
13430
  continue;
13198
- const name = parseSkillName(fs21.readFileSync(skillPath, "utf-8"));
13431
+ const name = parseSkillName(fs22.readFileSync(skillPath, "utf-8"));
13199
13432
  if (name && SAFE_NAME.test(name))
13200
13433
  out.set(name, skillPath);
13201
13434
  }
13202
13435
  return out;
13203
13436
  }
13204
13437
  function hasMarker(dir) {
13205
- return fs21.existsSync(path23.join(dir, OPENCODE_SKILL_MARKER));
13438
+ return fs22.existsSync(path24.join(dir, OPENCODE_SKILL_MARKER));
13206
13439
  }
13207
13440
  function syncOpencodeSkills(opts) {
13208
13441
  const result = { written: [], unchanged: [], removed: [], skipped: [] };
13209
13442
  const wanted = listSourceSkills(opts.sourceSkillsDir);
13210
- if (wanted.size === 0 && !fs21.existsSync(opts.sourceSkillsDir))
13443
+ if (wanted.size === 0 && !fs22.existsSync(opts.sourceSkillsDir))
13211
13444
  return result;
13212
13445
  if (!opts.dryRun)
13213
- fs21.mkdirSync(opts.skillsRoot, { recursive: true });
13446
+ fs22.mkdirSync(opts.skillsRoot, { recursive: true });
13214
13447
  for (const [name, srcPath] of wanted) {
13215
- const targetDir = path23.join(opts.skillsRoot, name);
13216
- const targetSkill = path23.join(targetDir, "SKILL.md");
13448
+ const targetDir = path24.join(opts.skillsRoot, name);
13449
+ const targetSkill = path24.join(targetDir, "SKILL.md");
13217
13450
  const managed = hasMarker(targetDir);
13218
- if (fs21.existsSync(targetSkill) && !managed) {
13451
+ if (fs22.existsSync(targetSkill) && !managed) {
13219
13452
  result.skipped.push({ name, reason: "foreign-collision" });
13220
13453
  continue;
13221
13454
  }
13222
- const current = fs21.existsSync(targetSkill) ? fs21.readFileSync(targetSkill) : null;
13223
- if (current && current.equals(fs21.readFileSync(srcPath))) {
13455
+ const current = fs22.existsSync(targetSkill) ? fs22.readFileSync(targetSkill) : null;
13456
+ if (current && current.equals(fs22.readFileSync(srcPath))) {
13224
13457
  if (!managed && !opts.dryRun) {
13225
- fs21.writeFileSync(path23.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
13458
+ fs22.writeFileSync(path24.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
13226
13459
  }
13227
13460
  result.unchanged.push(name);
13228
13461
  continue;
13229
13462
  }
13230
13463
  if (!opts.dryRun) {
13231
- fs21.mkdirSync(targetDir, { recursive: true });
13232
- fs21.copyFileSync(srcPath, targetSkill);
13233
- fs21.writeFileSync(path23.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
13464
+ fs22.mkdirSync(targetDir, { recursive: true });
13465
+ fs22.copyFileSync(srcPath, targetSkill);
13466
+ fs22.writeFileSync(path24.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
13234
13467
  }
13235
13468
  result.written.push(name);
13236
13469
  }
13237
- if (fs21.existsSync(opts.skillsRoot)) {
13238
- for (const entry of fs21.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
13470
+ if (fs22.existsSync(opts.skillsRoot)) {
13471
+ for (const entry of fs22.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
13239
13472
  if (!entry.isDirectory() || wanted.has(entry.name))
13240
13473
  continue;
13241
- const dir = path23.join(opts.skillsRoot, entry.name);
13474
+ const dir = path24.join(opts.skillsRoot, entry.name);
13242
13475
  if (!hasMarker(dir))
13243
13476
  continue;
13244
13477
  if (!opts.dryRun)
13245
- fs21.rmSync(dir, { recursive: true, force: true });
13478
+ fs22.rmSync(dir, { recursive: true, force: true });
13246
13479
  result.removed.push(entry.name);
13247
13480
  }
13248
13481
  }
@@ -13250,7 +13483,7 @@ function syncOpencodeSkills(opts) {
13250
13483
  }
13251
13484
  function syncShippedOpencodeSkills(opts) {
13252
13485
  return syncOpencodeSkills({
13253
- sourceSkillsDir: path23.join(opts.pkgRoot, "plugin", "skills"),
13486
+ sourceSkillsDir: path24.join(opts.pkgRoot, "plugin", "skills"),
13254
13487
  skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
13255
13488
  dryRun: opts.dryRun
13256
13489
  });
@@ -13258,7 +13491,7 @@ function syncShippedOpencodeSkills(opts) {
13258
13491
 
13259
13492
  // packages/agents/dist/projection/claude.js
13260
13493
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
13261
- import path24 from "path";
13494
+ import path25 from "path";
13262
13495
  import os13 from "os";
13263
13496
 
13264
13497
  // packages/agents/dist/codex/app-server-client.js
@@ -13269,12 +13502,12 @@ function _parseChunk(acc, chunk) {
13269
13502
  const out = [];
13270
13503
  let idx;
13271
13504
  while ((idx = acc.buf.indexOf("\n")) >= 0) {
13272
- const line = acc.buf.slice(0, idx);
13505
+ const line2 = acc.buf.slice(0, idx);
13273
13506
  acc.buf = acc.buf.slice(idx + 1);
13274
- if (!line.trim())
13507
+ if (!line2.trim())
13275
13508
  continue;
13276
13509
  try {
13277
- out.push(JSON.parse(line));
13510
+ out.push(JSON.parse(line2));
13278
13511
  } catch {
13279
13512
  }
13280
13513
  }
@@ -13996,9 +14229,9 @@ var OpencodeSseBridge = class {
13996
14229
  buf += decoder.decode(value, { stream: true });
13997
14230
  let nl;
13998
14231
  while ((nl = buf.indexOf("\n")) >= 0) {
13999
- const line = buf.slice(0, nl);
14232
+ const line2 = buf.slice(0, nl);
14000
14233
  buf = buf.slice(nl + 1);
14001
- this.handleLine(taskId, line);
14234
+ this.handleLine(taskId, line2);
14002
14235
  }
14003
14236
  }
14004
14237
  } finally {
@@ -14009,16 +14242,16 @@ var OpencodeSseBridge = class {
14009
14242
  }
14010
14243
  }
14011
14244
  handleLine(taskId, rawLine) {
14012
- let line = rawLine.trim();
14013
- if (!line)
14245
+ let line2 = rawLine.trim();
14246
+ if (!line2)
14014
14247
  return;
14015
- if (line.startsWith("data:"))
14016
- line = line.slice(5).trim();
14017
- if (!line.startsWith("{"))
14248
+ if (line2.startsWith("data:"))
14249
+ line2 = line2.slice(5).trim();
14250
+ if (!line2.startsWith("{"))
14018
14251
  return;
14019
14252
  let json2;
14020
14253
  try {
14021
- json2 = JSON.parse(line);
14254
+ json2 = JSON.parse(line2);
14022
14255
  } catch {
14023
14256
  return;
14024
14257
  }
@@ -14376,13 +14609,13 @@ function buildUserEnvelope(opts) {
14376
14609
  };
14377
14610
  }
14378
14611
  function writeLine(socketPath, envelope, deps) {
14379
- const line = `${JSON.stringify(envelope)}
14612
+ const line2 = `${JSON.stringify(envelope)}
14380
14613
  `;
14381
- if (Buffer.byteLength(line, "utf8") > MAX_LINE_BYTES) {
14614
+ if (Buffer.byteLength(line2, "utf8") > MAX_LINE_BYTES) {
14382
14615
  return Promise.resolve({
14383
14616
  ok: false,
14384
14617
  reason: "transport",
14385
- error: `line exceeds the receiver's 1 MiB buffer cap (${Buffer.byteLength(line, "utf8")} bytes)`
14618
+ error: `line exceeds the receiver's 1 MiB buffer cap (${Buffer.byteLength(line2, "utf8")} bytes)`
14386
14619
  });
14387
14620
  }
14388
14621
  return new Promise((resolve4) => {
@@ -14402,7 +14635,7 @@ function writeLine(socketPath, envelope, deps) {
14402
14635
  done({ ok: false, reason: "transport", error: `timeout after ${deps.timeoutMs ?? DEFAULT_TIMEOUT_MS}ms` });
14403
14636
  }, deps.timeoutMs ?? DEFAULT_TIMEOUT_MS);
14404
14637
  sock.on("connect", () => {
14405
- sock.write(line, () => {
14638
+ sock.write(line2, () => {
14406
14639
  clearTimeout(timer);
14407
14640
  try {
14408
14641
  sock.end();
@@ -14563,20 +14796,20 @@ var ClaudeReceiptListener = class {
14563
14796
  buf += chunk;
14564
14797
  let nl;
14565
14798
  while ((nl = buf.indexOf("\n")) !== -1) {
14566
- const line = buf.slice(0, nl);
14799
+ const line2 = buf.slice(0, nl);
14567
14800
  buf = buf.slice(nl + 1);
14568
- this.dispatch(line);
14801
+ this.dispatch(line2);
14569
14802
  }
14570
14803
  });
14571
14804
  conn.on("error", () => {
14572
14805
  });
14573
14806
  }
14574
- dispatch(line) {
14575
- if (!line.trim())
14807
+ dispatch(line2) {
14808
+ if (!line2.trim())
14576
14809
  return;
14577
14810
  let f;
14578
14811
  try {
14579
- f = JSON.parse(line);
14812
+ f = JSON.parse(line2);
14580
14813
  } catch {
14581
14814
  this.deps.log?.(`claude-receipt: discarded non-JSON frame`);
14582
14815
  return;
@@ -14603,9 +14836,9 @@ var ClaudeReceiptListener = class {
14603
14836
  };
14604
14837
 
14605
14838
  // packages/agents/dist/claude/api-key-approval.js
14606
- import fs22 from "fs";
14839
+ import fs23 from "fs";
14607
14840
  import os14 from "os";
14608
- import path25 from "path";
14841
+ import path26 from "path";
14609
14842
 
14610
14843
  // packages/agents/dist/opencode/http-channel.js
14611
14844
  init_dist2();
@@ -14697,10 +14930,10 @@ var OpencodeHttpChannel = class {
14697
14930
  return cached;
14698
14931
  const directory = this.directoryFor?.(taskId);
14699
14932
  const createdAfterMs = this.createdAfterFor?.(taskId);
14700
- for (const path28 of ["/session?", "/api/session?"]) {
14933
+ for (const path29 of ["/session?", "/api/session?"]) {
14701
14934
  let res;
14702
14935
  try {
14703
- res = await this.request(`http://127.0.0.1:${port}${path28}`, { method: "GET" });
14936
+ res = await this.request(`http://127.0.0.1:${port}${path29}`, { method: "GET" });
14704
14937
  } catch {
14705
14938
  return void 0;
14706
14939
  }
@@ -14878,13 +15111,13 @@ function parseDraftFromScreen(screen) {
14878
15111
  if (topHR === -1)
14879
15112
  return null;
14880
15113
  const inputLines = lines.slice(topHR + 1, bottomHR);
14881
- for (const line of inputLines) {
15114
+ for (const line2 of inputLines) {
14882
15115
  let extracted;
14883
- const boxMatch = line.match(/│\s*[>❯]\s+(.*?)\s*│/);
15116
+ const boxMatch = line2.match(/│\s*[>❯]\s+(.*?)\s*│/);
14884
15117
  if (boxMatch) {
14885
15118
  extracted = boxMatch[1].trim();
14886
15119
  } else {
14887
- const plainMatch = line.match(/^\s*[>❯]\s*(.*)$/);
15120
+ const plainMatch = line2.match(/^\s*[>❯]\s*(.*)$/);
14888
15121
  if (plainMatch)
14889
15122
  extracted = plainMatch[1].trim();
14890
15123
  }
@@ -14962,8 +15195,8 @@ function readInputBoxRaw(screen, opts) {
14962
15195
  if (topHR === -1)
14963
15196
  return null;
14964
15197
  const parts = [];
14965
- for (const line of lines.slice(topHR + 1, bottomHR)) {
14966
- let s = line.replace(/│/g, " ");
15198
+ for (const line2 of lines.slice(topHR + 1, bottomHR)) {
15199
+ let s = line2.replace(/│/g, " ");
14967
15200
  s = s.replace(/^\s*[>❯]\s?/, "");
14968
15201
  s = s.replace(/\s*[▌█▔▎▏]+\s*$/, "");
14969
15202
  parts.push(s);
@@ -15436,9 +15669,9 @@ var NotifierRegistry = class {
15436
15669
  };
15437
15670
 
15438
15671
  // packages/workspaces/dist/workspaces/obsidian.js
15439
- import fs23 from "fs/promises";
15672
+ import fs24 from "fs/promises";
15440
15673
  import { existsSync as existsSync11 } from "fs";
15441
- import path26 from "path";
15674
+ import path27 from "path";
15442
15675
 
15443
15676
  // packages/workspaces/dist/workspaces/registry.js
15444
15677
  init_dist();
@@ -15536,18 +15769,18 @@ var CmuxEventsBridge = class {
15536
15769
  this.buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
15537
15770
  let nl;
15538
15771
  while ((nl = this.buf.indexOf("\n")) >= 0) {
15539
- const line = this.buf.slice(0, nl);
15772
+ const line2 = this.buf.slice(0, nl);
15540
15773
  this.buf = this.buf.slice(nl + 1);
15541
- this.handleLine(line);
15774
+ this.handleLine(line2);
15542
15775
  }
15543
15776
  }
15544
15777
  handleLine(rawLine) {
15545
- const line = rawLine.trim();
15546
- if (!line || line[0] !== "{")
15778
+ const line2 = rawLine.trim();
15779
+ if (!line2 || line2[0] !== "{")
15547
15780
  return;
15548
15781
  let f;
15549
15782
  try {
15550
- f = JSON.parse(line);
15783
+ f = JSON.parse(line2);
15551
15784
  } catch {
15552
15785
  return;
15553
15786
  }
@@ -15988,9 +16221,9 @@ function defaultListFiles(dir) {
15988
16221
  return [];
15989
16222
  }
15990
16223
  }
15991
- function defaultReadFile(path28) {
16224
+ function defaultReadFile(path29) {
15992
16225
  try {
15993
- return readFileSync17(path28, "utf-8");
16226
+ return readFileSync17(path29, "utf-8");
15994
16227
  } catch {
15995
16228
  return void 0;
15996
16229
  }
@@ -16368,16 +16601,16 @@ function extractDetail(sub, payload) {
16368
16601
  }
16369
16602
  return void 0;
16370
16603
  }
16371
- function defaultReadFile2(path28) {
16604
+ function defaultReadFile2(path29) {
16372
16605
  try {
16373
- return readFileSync18(path28, "utf-8");
16606
+ return readFileSync18(path29, "utf-8");
16374
16607
  } catch {
16375
16608
  return void 0;
16376
16609
  }
16377
16610
  }
16378
- function defaultWriteFile(path28, content) {
16379
- mkdirSync8(path28.replace(/\/[^/]+$/, ""), { recursive: true });
16380
- writeFileSync11(path28, content, "utf-8");
16611
+ function defaultWriteFile(path29, content) {
16612
+ mkdirSync8(path29.replace(/\/[^/]+$/, ""), { recursive: true });
16613
+ writeFileSync11(path29, content, "utf-8");
16381
16614
  }
16382
16615
 
16383
16616
  // packages/workspaces/dist/crew-pane.js
@@ -16457,9 +16690,9 @@ init_dist();
16457
16690
 
16458
16691
  // packages/cli/src/lib/daemon-restart-broadcast.ts
16459
16692
  init_dist();
16460
- import path27 from "path";
16693
+ import path28 from "path";
16461
16694
  function statePath2(stateRoot) {
16462
- return path27.join(stateRoot, "daemon-restart-state.json");
16695
+ return path28.join(stateRoot, "daemon-restart-state.json");
16463
16696
  }
16464
16697
  function computeRestartSignature(version, buildMtimeMs) {
16465
16698
  return `${version}::${buildMtimeMs}`;
@@ -16508,7 +16741,7 @@ async function maybeBroadcastDaemonRestart(opts) {
16508
16741
 
16509
16742
  // packages/cli/src/lib/captain-channel-factory.ts
16510
16743
  import { createServer as createServer4, connect as netConnect } from "net";
16511
- import fs24 from "fs";
16744
+ import fs25 from "fs";
16512
16745
  import { join as join26 } from "path";
16513
16746
  import { randomUUID as randomUUID5 } from "crypto";
16514
16747
  import chalk2 from "chalk";
@@ -16517,15 +16750,15 @@ var shared;
16517
16750
  var registryEntryPath = () => join26(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
16518
16751
  function unregisterSenderIdentity() {
16519
16752
  try {
16520
- fs24.unlinkSync(registryEntryPath());
16753
+ fs25.unlinkSync(registryEntryPath());
16521
16754
  } catch {
16522
16755
  }
16523
16756
  }
16524
16757
  function registerSenderIdentity(socketPath) {
16525
16758
  try {
16526
16759
  unregisterSenderIdentity();
16527
- fs24.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
16528
- fs24.writeFileSync(
16760
+ fs25.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
16761
+ fs25.writeFileSync(
16529
16762
  registryEntryPath(),
16530
16763
  JSON.stringify({
16531
16764
  pid: process.pid,
@@ -16551,7 +16784,7 @@ async function sharedReceiptListener() {
16551
16784
  // must never be the reason we refuse to start.
16552
16785
  unlinkStale: (p) => {
16553
16786
  try {
16554
- fs24.unlinkSync(p);
16787
+ fs25.unlinkSync(p);
16555
16788
  } catch {
16556
16789
  }
16557
16790
  },
@@ -16576,7 +16809,7 @@ async function buildCaptainChannel() {
16576
16809
  // in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
16577
16810
  // missed and every captain ping reported accepted-unconfirmed.
16578
16811
  statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
16579
- wire: (p, e) => writeLine(p, e, { connect: (path28) => netConnect(path28) }),
16812
+ wire: (p, e) => writeLine(p, e, { connect: (path29) => netConnect(path29) }),
16580
16813
  receipts,
16581
16814
  newMsgId: () => randomUUID5(),
16582
16815
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),