squadrant 0.28.1 → 0.29.0

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.
@@ -417,6 +417,18 @@ var init_knowledge = __esm({
417
417
  }
418
418
  });
419
419
 
420
+ // packages/shared/dist/workspace.js
421
+ import fs2 from "fs";
422
+ import os3 from "os";
423
+ import path5 from "path";
424
+ var workspaceRoot, workspacePath;
425
+ var init_workspace = __esm({
426
+ "packages/shared/dist/workspace.js"() {
427
+ workspaceRoot = () => process.env.SQUADRANT_WORKSPACE_DIR || path5.join(os3.homedir(), "squadrant", "workspace");
428
+ workspacePath = (project) => path5.join(workspaceRoot(), project);
429
+ }
430
+ });
431
+
420
432
  // packages/shared/dist/router-model.js
421
433
  function resolveRouterModel(model, agentName, router) {
422
434
  if (!model)
@@ -484,22 +496,22 @@ function defaultCmuxConfigPath() {
484
496
  return join(homedir(), ".config", "cmux", "cmux.json");
485
497
  }
486
498
  function ensureSocketAutomation(opts = {}) {
487
- const path43 = opts.path ?? defaultCmuxConfigPath();
488
- if (!existsSync(path43)) {
489
- mkdirSync(dirname(path43), { recursive: true });
490
- writeFileSync(path43, MINIMAL_TEMPLATE);
491
- return { path: path43, changed: true, alreadySet: false };
499
+ const path44 = opts.path ?? defaultCmuxConfigPath();
500
+ if (!existsSync(path44)) {
501
+ mkdirSync(dirname(path44), { recursive: true });
502
+ writeFileSync(path44, MINIMAL_TEMPLATE);
503
+ return { path: path44, changed: true, alreadySet: false };
492
504
  }
493
- const text = readFileSync(path43, "utf-8");
505
+ const text = readFileSync(path44, "utf-8");
494
506
  const current = parse(text)?.automation?.socketControlMode;
495
507
  if (current === AUTOMATION_MODE) {
496
- return { path: path43, changed: false, alreadySet: true };
508
+ return { path: path44, changed: false, alreadySet: true };
497
509
  }
498
510
  const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
499
511
  formattingOptions: { insertSpaces: true, tabSize: 2 }
500
512
  });
501
- writeFileSync(path43, applyEdits(text, edits));
502
- return { path: path43, changed: true, alreadySet: false };
513
+ writeFileSync(path44, applyEdits(text, edits));
514
+ return { path: path44, changed: true, alreadySet: false };
503
515
  }
504
516
  var SOCKET_CONTROL_MODE_PATH, AUTOMATION_MODE, MINIMAL_TEMPLATE;
505
517
  var init_cmux_config = __esm({
@@ -642,16 +654,75 @@ writeFileSync(resultFile, JSON.stringify(result));
642
654
  }
643
655
  });
644
656
 
645
- // packages/shared/dist/lib/cmux-autoconfig.js
646
- import { existsSync as existsSync4, rmSync as rmSync2 } from "fs";
657
+ // packages/shared/dist/lib/state-paths.js
658
+ import { cpSync, existsSync as existsSync4, readdirSync, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
647
659
  import { homedir as homedir3 } from "os";
648
- import { join as join4 } from "path";
660
+ import { dirname as dirname2, join as join4, resolve } from "path";
661
+ function isolatedConfigDir() {
662
+ const cfg = process.env.SQUADRANT_CONFIG;
663
+ if (!cfg || resolve(cfg) === join4(defaultConfigDir(), "config.json"))
664
+ return null;
665
+ return dirname2(resolve(cfg));
666
+ }
667
+ function stateRoot() {
668
+ if (process.env.SQUADRANT_STATE_DIR)
669
+ return process.env.SQUADRANT_STATE_DIR;
670
+ const isolated = isolatedConfigDir();
671
+ if (isolated)
672
+ return join4(isolated, "state");
673
+ return join4(process.env.XDG_STATE_HOME || join4(homedir3(), ".local", "state"), "squadrant");
674
+ }
675
+ function logsRoot() {
676
+ return join4(stateRoot(), "logs");
677
+ }
678
+ function daemonLogPath() {
679
+ return join4(logsRoot(), "squadrantd.log");
680
+ }
681
+ function legacyStateDir() {
682
+ return join4(isolatedConfigDir() ?? defaultConfigDir(), "state");
683
+ }
684
+ function legacyDaemonLogPath() {
685
+ return join4(isolatedConfigDir() ?? defaultConfigDir(), "squadrantd.log");
686
+ }
687
+ function stateSeedMarkerPath(root = stateRoot()) {
688
+ return join4(root, ".seeded-from-legacy");
689
+ }
690
+ function resolveReadPath(newPath, legacyPath) {
691
+ if (existsSync4(newPath) || !existsSync4(legacyPath))
692
+ return newPath;
693
+ return legacyPath;
694
+ }
695
+ function seedStateFromLegacy(opts = {}) {
696
+ const root = opts.root ?? stateRoot();
697
+ const legacy = opts.legacy ?? legacyStateDir();
698
+ if (resolve(root) === resolve(legacy))
699
+ return { seeded: false, reason: "same-dir" };
700
+ const marker = stateSeedMarkerPath(root);
701
+ if (existsSync4(marker))
702
+ return { seeded: false, reason: "already-seeded" };
703
+ if (!existsSync4(legacy) || readdirSync(legacy).length === 0)
704
+ return { seeded: false, reason: "no-legacy-data" };
705
+ mkdirSync2(root, { recursive: true });
706
+ cpSync(legacy, root, { recursive: true, force: false, errorOnExist: false });
707
+ writeFileSync3(marker, JSON.stringify({ from: legacy, at: (/* @__PURE__ */ new Date()).toISOString() }) + "\n");
708
+ return { seeded: true, reason: "seeded" };
709
+ }
710
+ var defaultConfigDir;
711
+ var init_state_paths = __esm({
712
+ "packages/shared/dist/lib/state-paths.js"() {
713
+ defaultConfigDir = () => join4(homedir3(), ".config", "squadrant");
714
+ }
715
+ });
716
+
717
+ // packages/shared/dist/lib/cmux-autoconfig.js
718
+ import { existsSync as existsSync5, rmSync as rmSync2 } from "fs";
719
+ import { join as join5 } from "path";
649
720
  function defaultStatePath() {
650
- return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
721
+ return join5(stateRoot(), "cmux-autoconfig.json");
651
722
  }
652
- function readState(path43) {
723
+ function readState(path44) {
653
724
  try {
654
- return JSON.parse(readConfigFileSync(path43));
725
+ return JSON.parse(readConfigFileSync(path44));
655
726
  } catch {
656
727
  return {};
657
728
  }
@@ -671,7 +742,7 @@ async function ensureCmuxAutoConfig(opts = {}) {
671
742
  promptedThisRun = true;
672
743
  }
673
744
  } else if (verdict === "reachable") {
674
- if (existsSync4(statePath3))
745
+ if (existsSync5(statePath3))
675
746
  rmSync2(statePath3, { force: true });
676
747
  }
677
748
  return {
@@ -688,6 +759,7 @@ var init_cmux_autoconfig = __esm({
688
759
  init_cmux_config();
689
760
  init_cmux_probe();
690
761
  init_config_io();
762
+ init_state_paths();
691
763
  }
692
764
  });
693
765
 
@@ -723,14 +795,14 @@ var init_config_version = __esm({
723
795
  });
724
796
 
725
797
  // packages/shared/dist/lib/update-check.js
726
- import fs2 from "fs";
727
- import path5 from "path";
728
- import os3 from "os";
798
+ import fs3 from "fs";
799
+ import path6 from "path";
800
+ import os4 from "os";
729
801
  import https from "https";
730
802
  var UPDATE_CHECK_STATE_PATH, CHECK_INTERVAL_MS, FAILURE_RETRY_MS;
731
803
  var init_update_check = __esm({
732
804
  "packages/shared/dist/lib/update-check.js"() {
733
- UPDATE_CHECK_STATE_PATH = path5.join(os3.homedir(), ".config", "squadrant", "update-check.json");
805
+ UPDATE_CHECK_STATE_PATH = path6.join(os4.homedir(), ".config", "squadrant", "update-check.json");
734
806
  CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
735
807
  FAILURE_RETRY_MS = 60 * 60 * 1e3;
736
808
  }
@@ -738,10 +810,10 @@ var init_update_check = __esm({
738
810
 
739
811
  // packages/shared/dist/lib/git-worktree.js
740
812
  import { execFileSync as execFileSync2 } from "child_process";
741
- import fs3 from "fs";
742
- import path6 from "path";
813
+ import fs4 from "fs";
814
+ import path7 from "path";
743
815
  function worktreePath(repoRoot, worktreeDir, project, name) {
744
- return path6.resolve(repoRoot, worktreeDir, `${project}-${name}`);
816
+ return path7.resolve(repoRoot, worktreeDir, `${project}-${name}`);
745
817
  }
746
818
  function crewBranch(name) {
747
819
  return `crew/${name}`;
@@ -750,11 +822,11 @@ function ensureSpotlightExcluded(repoRoot, worktreeDir) {
750
822
  if (process.platform !== "darwin")
751
823
  return;
752
824
  try {
753
- const dir = path6.resolve(repoRoot, worktreeDir);
754
- fs3.mkdirSync(dir, { recursive: true });
755
- const marker = path6.join(dir, ".metadata_never_index");
756
- if (!fs3.existsSync(marker))
757
- fs3.writeFileSync(marker, "");
825
+ const dir = path7.resolve(repoRoot, worktreeDir);
826
+ fs4.mkdirSync(dir, { recursive: true });
827
+ const marker = path7.join(dir, ".metadata_never_index");
828
+ if (!fs4.existsSync(marker))
829
+ fs4.writeFileSync(marker, "");
758
830
  } catch {
759
831
  }
760
832
  }
@@ -816,15 +888,15 @@ function addWorktree(spec) {
816
888
  return wt;
817
889
  }
818
890
  function installWorktreeDependencies(wt) {
819
- if (!fs3.existsSync(path6.join(wt, "package.json")))
891
+ if (!fs4.existsSync(path7.join(wt, "package.json")))
820
892
  return;
821
- if (fs3.existsSync(path6.join(wt, "pnpm-lock.yaml"))) {
893
+ if (fs4.existsSync(path7.join(wt, "pnpm-lock.yaml"))) {
822
894
  execFileSync2("pnpm", ["-C", wt, "install", "--frozen-lockfile"], { stdio: "pipe" });
823
- } else if (fs3.existsSync(path6.join(wt, "yarn.lock"))) {
895
+ } else if (fs4.existsSync(path7.join(wt, "yarn.lock"))) {
824
896
  execFileSync2("yarn", ["install", "--frozen-lockfile"], { cwd: wt, stdio: "pipe" });
825
- } else if (fs3.existsSync(path6.join(wt, "package-lock.json"))) {
897
+ } else if (fs4.existsSync(path7.join(wt, "package-lock.json"))) {
826
898
  execFileSync2("npm", ["ci"], { cwd: wt, stdio: "pipe" });
827
- } else if (fs3.existsSync(path6.join(wt, "bun.lockb"))) {
899
+ } else if (fs4.existsSync(path7.join(wt, "bun.lockb"))) {
828
900
  execFileSync2("bun", ["install", "--frozen-lockfile"], { cwd: wt, stdio: "pipe" });
829
901
  } else {
830
902
  process.stderr.write(`worktree ${wt}: package.json present but no lockfile \u2014 dependencies not installed; local typechecks/tests may resolve against the main checkout instead of this worktree.
@@ -843,7 +915,7 @@ function worktreeDirtyFiles(wtPath) {
843
915
  }
844
916
  function removeGeneratedWorktreeFiles(wtPath) {
845
917
  for (const [, file] of worktreeStatus(wtPath).filter(isGeneratedUntracked)) {
846
- fs3.rmSync(path6.join(wtPath, file), { force: true });
918
+ fs4.rmSync(path7.join(wtPath, file), { force: true });
847
919
  }
848
920
  }
849
921
  function removeWorktree(repoRoot, wtPath, opts) {
@@ -859,15 +931,15 @@ var init_git_worktree = __esm({
859
931
  });
860
932
 
861
933
  // packages/shared/dist/lib/resolve-text-input.js
862
- import fs4 from "fs";
934
+ import fs5 from "fs";
863
935
  var init_resolve_text_input = __esm({
864
936
  "packages/shared/dist/lib/resolve-text-input.js"() {
865
937
  }
866
938
  });
867
939
 
868
940
  // packages/shared/dist/lib/runtime-sync.js
869
- import fs5 from "fs";
870
- import path7 from "path";
941
+ import fs6 from "fs";
942
+ import path8 from "path";
871
943
  var init_runtime_sync = __esm({
872
944
  "packages/shared/dist/lib/runtime-sync.js"() {
873
945
  }
@@ -909,8 +981,8 @@ var init_tool_compat = __esm({
909
981
  });
910
982
 
911
983
  // packages/shared/dist/lib/canonical-source.js
912
- import fs6 from "fs";
913
- import path8 from "path";
984
+ import fs7 from "fs";
985
+ import path9 from "path";
914
986
  var init_canonical_source = __esm({
915
987
  "packages/shared/dist/lib/canonical-source.js"() {
916
988
  }
@@ -918,8 +990,8 @@ var init_canonical_source = __esm({
918
990
 
919
991
  // packages/shared/dist/lib/daily-logs.js
920
992
  import { execSync } from "child_process";
921
- import fs7 from "fs";
922
- import path9 from "path";
993
+ import fs8 from "fs";
994
+ import path10 from "path";
923
995
  import matter from "gray-matter";
924
996
  var init_daily_logs = __esm({
925
997
  "packages/shared/dist/lib/daily-logs.js"() {
@@ -942,12 +1014,6 @@ var init_session_name = __esm({
942
1014
  }
943
1015
  });
944
1016
 
945
- // packages/shared/dist/lib/vault-layout.js
946
- var init_vault_layout = __esm({
947
- "packages/shared/dist/lib/vault-layout.js"() {
948
- }
949
- });
950
-
951
1017
  // packages/shared/dist/daemon-keys.js
952
1018
  var init_daemon_keys = __esm({
953
1019
  "packages/shared/dist/daemon-keys.js"() {
@@ -962,6 +1028,7 @@ var init_dist = __esm({
962
1028
  init_project_config();
963
1029
  init_effort();
964
1030
  init_knowledge();
1031
+ init_workspace();
965
1032
  init_router_model();
966
1033
  init_runtime();
967
1034
  init_liveness();
@@ -985,7 +1052,7 @@ var init_dist = __esm({
985
1052
  init_canonical_source();
986
1053
  init_daily_logs();
987
1054
  init_session_name();
988
- init_vault_layout();
1055
+ init_state_paths();
989
1056
  init_daemon_keys();
990
1057
  }
991
1058
  });
@@ -1670,33 +1737,33 @@ var init_reduce = __esm({
1670
1737
  });
1671
1738
 
1672
1739
  // packages/core/dist/mailbox.js
1673
- import { promises as fs8 } from "fs";
1674
- import { join as join5 } from "path";
1740
+ import { promises as fs9 } from "fs";
1741
+ import { join as join6 } from "path";
1675
1742
  import { randomUUID } from "crypto";
1676
- function inboxDir(stateRoot) {
1677
- return join5(stateRoot, "inbox");
1743
+ function inboxDir(stateRoot2) {
1744
+ return join6(stateRoot2, "inbox");
1678
1745
  }
1679
- function logPath(stateRoot, project) {
1680
- return join5(inboxDir(stateRoot), `${project}.log`);
1746
+ function logPath(stateRoot2, project) {
1747
+ return join6(inboxDir(stateRoot2), `${project}.log`);
1681
1748
  }
1682
1749
  function extractPayload(event) {
1683
1750
  const { type: _type, id: _id, ...payload } = event;
1684
1751
  return payload;
1685
1752
  }
1686
- async function listRotatedOldestFirst(stateRoot, project) {
1687
- const dir = inboxDir(stateRoot);
1753
+ async function listRotatedOldestFirst(stateRoot2, project) {
1754
+ const dir = inboxDir(stateRoot2);
1688
1755
  let entries;
1689
1756
  try {
1690
- entries = await fs8.readdir(dir);
1757
+ entries = await fs9.readdir(dir);
1691
1758
  } catch {
1692
1759
  return [];
1693
1760
  }
1694
1761
  const prefix = `${project}.log.`;
1695
- return entries.filter((e) => e.startsWith(prefix) && /^\d+$/.test(e.slice(prefix.length))).map((e) => ({ name: e, n: Number(e.slice(prefix.length)) })).sort((a, b) => b.n - a.n).map((e) => join5(dir, e.name));
1762
+ return entries.filter((e) => e.startsWith(prefix) && /^\d+$/.test(e.slice(prefix.length))).map((e) => ({ name: e, n: Number(e.slice(prefix.length)) })).sort((a, b) => b.n - a.n).map((e) => join6(dir, e.name));
1696
1763
  }
1697
1764
  async function readMaxSeqFromFile(file) {
1698
1765
  try {
1699
- const buf = await fs8.readFile(file, "utf-8");
1766
+ const buf = await fs9.readFile(file, "utf-8");
1700
1767
  if (!buf.trim())
1701
1768
  return 0;
1702
1769
  const lines = buf.trim().split("\n");
@@ -1715,11 +1782,11 @@ async function readMaxSeqFromFile(file) {
1715
1782
  throw e;
1716
1783
  }
1717
1784
  }
1718
- async function readMaxSeq(stateRoot, project) {
1785
+ async function readMaxSeq(stateRoot2, project) {
1719
1786
  let max = 0;
1720
1787
  const files = [
1721
- logPath(stateRoot, project),
1722
- ...await listRotatedOldestFirst(stateRoot, project)
1788
+ logPath(stateRoot2, project),
1789
+ ...await listRotatedOldestFirst(stateRoot2, project)
1723
1790
  ];
1724
1791
  for (const file of files) {
1725
1792
  const seq2 = await readMaxSeqFromFile(file);
@@ -1734,15 +1801,15 @@ function withProjectLock(project, fn) {
1734
1801
  projectLocks.set(project, next.catch(() => void 0));
1735
1802
  return next;
1736
1803
  }
1737
- function appendEntry(stateRoot, project, build) {
1804
+ function appendEntry(stateRoot2, project, build) {
1738
1805
  return withProjectLock(project, async () => {
1739
- const dir = inboxDir(stateRoot);
1740
- await fs8.mkdir(dir, { recursive: true });
1741
- const file = logPath(stateRoot, project);
1742
- const lastSeq = await readMaxSeq(stateRoot, project);
1806
+ const dir = inboxDir(stateRoot2);
1807
+ await fs9.mkdir(dir, { recursive: true });
1808
+ const file = logPath(stateRoot2, project);
1809
+ const lastSeq = await readMaxSeq(stateRoot2, project);
1743
1810
  const seq2 = lastSeq + 1;
1744
1811
  const entry = build(seq2);
1745
- await fs8.appendFile(file, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
1812
+ await fs9.appendFile(file, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
1746
1813
  return seq2;
1747
1814
  });
1748
1815
  }
@@ -1767,13 +1834,13 @@ async function appendCaptainMessage(opts) {
1767
1834
  message: opts.text
1768
1835
  }));
1769
1836
  }
1770
- function cursorPath(stateRoot, project, subscriber) {
1771
- return join5(inboxDir(stateRoot), `${project}.${subscriber}.cursor`);
1837
+ function cursorPath(stateRoot2, project, subscriber) {
1838
+ return join6(inboxDir(stateRoot2), `${project}.${subscriber}.cursor`);
1772
1839
  }
1773
1840
  async function readCursor(opts) {
1774
1841
  let buf;
1775
1842
  try {
1776
- buf = await fs8.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), "utf-8");
1843
+ buf = await fs9.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), "utf-8");
1777
1844
  } catch (e) {
1778
1845
  if (e.code === "ENOENT")
1779
1846
  return null;
@@ -1800,7 +1867,7 @@ async function waitForCaptainDelivery(opts) {
1800
1867
  }
1801
1868
  }
1802
1869
  async function writeCursor(opts) {
1803
- await fs8.mkdir(inboxDir(opts.stateRoot), { recursive: true });
1870
+ await fs9.mkdir(inboxDir(opts.stateRoot), { recursive: true });
1804
1871
  const dest = cursorPath(opts.stateRoot, opts.project, opts.subscriber);
1805
1872
  const tmp = `${dest}.${process.pid}.${randomUUID()}.tmp`;
1806
1873
  const data = {
@@ -1808,7 +1875,7 @@ async function writeCursor(opts) {
1808
1875
  subscriber: opts.subscriber,
1809
1876
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1810
1877
  };
1811
- const handle = await fs8.open(tmp, "w");
1878
+ const handle = await fs9.open(tmp, "w");
1812
1879
  try {
1813
1880
  await handle.writeFile(JSON.stringify(data), { encoding: "utf-8" });
1814
1881
  await handle.sync();
@@ -1816,9 +1883,9 @@ async function writeCursor(opts) {
1816
1883
  await handle.close();
1817
1884
  }
1818
1885
  try {
1819
- await fs8.rename(tmp, dest);
1886
+ await fs9.rename(tmp, dest);
1820
1887
  } catch (e) {
1821
- await fs8.unlink(tmp).catch(() => {
1888
+ await fs9.unlink(tmp).catch(() => {
1822
1889
  });
1823
1890
  throw e;
1824
1891
  }
@@ -1829,7 +1896,7 @@ async function* readFromCursor(opts) {
1829
1896
  for (const file of files) {
1830
1897
  let buf;
1831
1898
  try {
1832
- buf = await fs8.readFile(file, "utf-8");
1899
+ buf = await fs9.readFile(file, "utf-8");
1833
1900
  } catch (e) {
1834
1901
  if (e.code === "ENOENT")
1835
1902
  continue;
@@ -1849,13 +1916,13 @@ async function* readFromCursor(opts) {
1849
1916
  }
1850
1917
  }
1851
1918
  }
1852
- async function mailboxStats(stateRoot, project) {
1853
- const file = logPath(stateRoot, project);
1854
- const rotated = await listRotatedOldestFirst(stateRoot, project);
1919
+ async function mailboxStats(stateRoot2, project) {
1920
+ const file = logPath(stateRoot2, project);
1921
+ const rotated = await listRotatedOldestFirst(stateRoot2, project);
1855
1922
  let sizeBytes = 0;
1856
1923
  for (const f of [file, ...rotated]) {
1857
1924
  try {
1858
- sizeBytes += (await fs8.stat(f)).size;
1925
+ sizeBytes += (await fs9.stat(f)).size;
1859
1926
  } catch (e) {
1860
1927
  if (e.code !== "ENOENT")
1861
1928
  throw e;
@@ -1863,7 +1930,7 @@ async function mailboxStats(stateRoot, project) {
1863
1930
  }
1864
1931
  const oldestFile = rotated[0] ?? file;
1865
1932
  return {
1866
- maxSeq: await readMaxSeq(stateRoot, project),
1933
+ maxSeq: await readMaxSeq(stateRoot2, project),
1867
1934
  sizeBytes,
1868
1935
  oldestEntryAgeMs: await oldestEntryAgeMs(oldestFile),
1869
1936
  rotationCount: rotated.length
@@ -1871,7 +1938,7 @@ async function mailboxStats(stateRoot, project) {
1871
1938
  }
1872
1939
  async function oldestEntryAgeMs(file) {
1873
1940
  try {
1874
- const buf = await fs8.readFile(file, "utf-8");
1941
+ const buf = await fs9.readFile(file, "utf-8");
1875
1942
  const firstLine = buf.split("\n").find((l) => l.trim());
1876
1943
  if (!firstLine)
1877
1944
  return 0;
@@ -1886,7 +1953,7 @@ async function rotateIfNeeded(opts) {
1886
1953
  const file = logPath(opts.stateRoot, opts.project);
1887
1954
  let size = 0;
1888
1955
  try {
1889
- size = (await fs8.stat(file)).size;
1956
+ size = (await fs9.stat(file)).size;
1890
1957
  } catch (e) {
1891
1958
  if (e.code === "ENOENT")
1892
1959
  return { rotated: false };
@@ -1902,22 +1969,22 @@ async function rotateIfNeeded(opts) {
1902
1969
  const dst = `${file}.${n + 1}`;
1903
1970
  if (n + 1 > opts.keepCount) {
1904
1971
  try {
1905
- await fs8.unlink(src);
1972
+ await fs9.unlink(src);
1906
1973
  } catch (e) {
1907
1974
  if (e.code !== "ENOENT")
1908
1975
  throw e;
1909
1976
  }
1910
1977
  } else {
1911
1978
  try {
1912
- await fs8.rename(src, dst);
1979
+ await fs9.rename(src, dst);
1913
1980
  } catch (e) {
1914
1981
  if (e.code !== "ENOENT")
1915
1982
  throw e;
1916
1983
  }
1917
1984
  }
1918
1985
  }
1919
- await fs8.rename(file, `${file}.1`);
1920
- await fs8.writeFile(file, "", { encoding: "utf-8" });
1986
+ await fs9.rename(file, `${file}.1`);
1987
+ await fs9.writeFile(file, "", { encoding: "utf-8" });
1921
1988
  return { rotated: true, from: file, to: `${file}.1` };
1922
1989
  });
1923
1990
  }
@@ -1930,7 +1997,7 @@ var init_mailbox = __esm({
1930
1997
 
1931
1998
  // packages/core/dist/protocol.js
1932
1999
  import { createServer, createConnection } from "net";
1933
- import { existsSync as existsSync5, unlinkSync, chmodSync } from "fs";
2000
+ import { existsSync as existsSync6, unlinkSync, chmodSync } from "fs";
1934
2001
  function encodeMsg(obj) {
1935
2002
  return JSON.stringify(obj) + "\n";
1936
2003
  }
@@ -1975,7 +2042,7 @@ function startServer(sockPath, handlerOrCallbacks, onListenError = defaultListen
1975
2042
  const { handler, onAttach, onAttachInbound, onAttachClose } = callbacks;
1976
2043
  const setIntervalFn = deps.setInterval ?? setInterval;
1977
2044
  const clearIntervalFn = deps.clearInterval ?? clearInterval;
1978
- if (existsSync5(sockPath)) {
2045
+ if (existsSync6(sockPath)) {
1979
2046
  try {
1980
2047
  unlinkSync(sockPath);
1981
2048
  } catch {
@@ -2053,9 +2120,9 @@ function startServer(sockPath, handlerOrCallbacks, onListenError = defaultListen
2053
2120
  return server;
2054
2121
  }
2055
2122
  function isDaemonSocketLive(sockPath, timeoutMs = 500) {
2056
- return new Promise((resolve4) => {
2057
- if (!existsSync5(sockPath)) {
2058
- resolve4(false);
2123
+ return new Promise((resolve5) => {
2124
+ if (!existsSync6(sockPath)) {
2125
+ resolve5(false);
2059
2126
  return;
2060
2127
  }
2061
2128
  const conn = createConnection(sockPath);
@@ -2064,7 +2131,7 @@ function isDaemonSocketLive(sockPath, timeoutMs = 500) {
2064
2131
  conn.destroy();
2065
2132
  } catch {
2066
2133
  }
2067
- resolve4(v2);
2134
+ resolve5(v2);
2068
2135
  };
2069
2136
  const timer = setTimeout(() => finish(false), timeoutMs);
2070
2137
  conn.on("connect", () => {
@@ -2078,7 +2145,7 @@ function isDaemonSocketLive(sockPath, timeoutMs = 500) {
2078
2145
  });
2079
2146
  }
2080
2147
  function sendRequest(sockPath, msg, timeoutMs = 5e3) {
2081
- return new Promise((resolve4, reject) => {
2148
+ return new Promise((resolve5, reject) => {
2082
2149
  const conn = createConnection(sockPath);
2083
2150
  const dec = createDecoder();
2084
2151
  const timer = setTimeout(() => {
@@ -2094,7 +2161,7 @@ function sendRequest(sockPath, msg, timeoutMs = 5e3) {
2094
2161
  if (m._v !== void 0 && m._v !== PROTOCOL_VERSION) {
2095
2162
  reject(new Error(`squadrantd protocol v${m._v}, this client expects v${PROTOCOL_VERSION} \u2014 upgrade squadrantd or this CLI`));
2096
2163
  } else if (m.ok) {
2097
- resolve4(m.reply);
2164
+ resolve5(m.reply);
2098
2165
  } else {
2099
2166
  reject(new Error(m.error));
2100
2167
  }
@@ -2243,8 +2310,8 @@ var init_liveness2 = __esm({
2243
2310
  });
2244
2311
 
2245
2312
  // packages/core/dist/store.js
2246
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, readdirSync, renameSync, writeFileSync as writeFileSync3, existsSync as existsSync6, rmSync as rmSync3, statSync } from "fs";
2247
- import { join as join6, resolve, sep } from "path";
2313
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync as readdirSync2, renameSync, writeFileSync as writeFileSync4, existsSync as existsSync7, rmSync as rmSync3, statSync } from "fs";
2314
+ import { join as join7, resolve as resolve2, sep } from "path";
2248
2315
  function safeSegment(kind, s) {
2249
2316
  if (typeof s !== "string" || s.length === 0) {
2250
2317
  throw new Error(`invalid ${kind}: must be a non-empty string`);
@@ -2263,19 +2330,19 @@ function isTaskRecord(r) {
2263
2330
  return typeof rec.id === "string" && rec.id.length > 0 && typeof rec.project === "string" && rec.project.length > 0;
2264
2331
  }
2265
2332
  function createStore(root) {
2266
- const rootResolved = resolve(root);
2333
+ const rootResolved = resolve2(root);
2267
2334
  const assertUnderRoot = (target) => {
2268
- const r = resolve(target);
2335
+ const r = resolve2(target);
2269
2336
  if (r !== rootResolved && !r.startsWith(rootResolved + sep)) {
2270
2337
  throw new Error(`path escapes state root: ${target}`);
2271
2338
  }
2272
2339
  return target;
2273
2340
  };
2274
- const projDir = (p) => assertUnderRoot(join6(root, safeSegment("project", p)));
2275
- const taskFile = (p, id) => assertUnderRoot(join6(projDir(p), `${safeSegment("id", id)}.json`));
2341
+ const projDir = (p) => assertUnderRoot(join7(root, safeSegment("project", p)));
2342
+ const taskFile = (p, id) => assertUnderRoot(join7(projDir(p), `${safeSegment("id", id)}.json`));
2276
2343
  const readRecord = (project, id) => {
2277
2344
  const f = taskFile(project, id);
2278
- if (!existsSync6(f))
2345
+ if (!existsSync7(f))
2279
2346
  return void 0;
2280
2347
  try {
2281
2348
  return JSON.parse(readFileSync4(f, "utf-8"));
@@ -2290,10 +2357,10 @@ function createStore(root) {
2290
2357
  console.error(`[squadrant] REJECTED terminal\u2192terminal overwrite of ${rec.project}/${rec.id}: already ${existing.state}/${existing.lastEvent} \u2014 refusing ${rec.state}/${rec.lastEvent}; original terminal record preserved (#595)`);
2291
2358
  return;
2292
2359
  }
2293
- mkdirSync2(projDir(rec.project), { recursive: true });
2360
+ mkdirSync3(projDir(rec.project), { recursive: true });
2294
2361
  const dest = taskFile(rec.project, rec.id);
2295
2362
  const tmp = `${dest}.tmp`;
2296
- writeFileSync3(tmp, JSON.stringify(rec, null, 2));
2363
+ writeFileSync4(tmp, JSON.stringify(rec, null, 2));
2297
2364
  renameSync(tmp, dest);
2298
2365
  },
2299
2366
  get(project, id) {
@@ -2301,22 +2368,22 @@ function createStore(root) {
2301
2368
  },
2302
2369
  list(project) {
2303
2370
  const d = projDir(project);
2304
- if (!existsSync6(d))
2371
+ if (!existsSync7(d))
2305
2372
  return [];
2306
- return readdirSync(d).filter((n) => n.endsWith(".json")).map((n) => {
2373
+ return readdirSync2(d).filter((n) => n.endsWith(".json")).map((n) => {
2307
2374
  try {
2308
- return JSON.parse(readFileSync4(join6(d, n), "utf-8"));
2375
+ return JSON.parse(readFileSync4(join7(d, n), "utf-8"));
2309
2376
  } catch {
2310
2377
  return void 0;
2311
2378
  }
2312
2379
  }).filter(isTaskRecord);
2313
2380
  },
2314
2381
  listAll() {
2315
- if (!existsSync6(root))
2382
+ if (!existsSync7(root))
2316
2383
  return [];
2317
- return readdirSync(root).filter((p) => {
2384
+ return readdirSync2(root).filter((p) => {
2318
2385
  try {
2319
- return statSync(join6(root, p)).isDirectory();
2386
+ return statSync(join7(root, p)).isDirectory();
2320
2387
  } catch {
2321
2388
  return false;
2322
2389
  }
@@ -2324,12 +2391,12 @@ function createStore(root) {
2324
2391
  },
2325
2392
  quarantine(project, id) {
2326
2393
  const f = taskFile(project, id);
2327
- if (existsSync6(f))
2394
+ if (existsSync7(f))
2328
2395
  renameSync(f, `${f}.corrupt.${Date.now()}`);
2329
2396
  },
2330
2397
  delete(project, id) {
2331
2398
  const f = taskFile(project, id);
2332
- if (existsSync6(f))
2399
+ if (existsSync7(f))
2333
2400
  rmSync3(f);
2334
2401
  }
2335
2402
  };
@@ -2342,11 +2409,11 @@ var init_store = __esm({
2342
2409
 
2343
2410
  // packages/core/dist/work-store.js
2344
2411
  import { homedir as homedir4 } from "os";
2345
- import { join as join7, resolve as resolve2, sep as sep2 } from "path";
2412
+ import { join as join8, resolve as resolve3, sep as sep2 } from "path";
2346
2413
  import { randomBytes } from "crypto";
2347
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, renameSync as renameSync2, writeFileSync as writeFileSync4, existsSync as existsSync7, rmSync as rmSync4, statSync as statSync2 } from "fs";
2414
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, readdirSync as readdirSync3, renameSync as renameSync2, writeFileSync as writeFileSync5, existsSync as existsSync8, rmSync as rmSync4, statSync as statSync2 } from "fs";
2348
2415
  function defaultWorkRoot() {
2349
- return join7(homedir4(), ".config", "squadrant", "work");
2416
+ return join8(homedir4(), ".config", "squadrant", "work");
2350
2417
  }
2351
2418
  function safeSegment2(kind, s) {
2352
2419
  if (typeof s !== "string" || s.length === 0) {
@@ -2360,27 +2427,27 @@ function safeSegment2(kind, s) {
2360
2427
  return s;
2361
2428
  }
2362
2429
  function createWorkStore(root = defaultWorkRoot()) {
2363
- const rootResolved = resolve2(root);
2430
+ const rootResolved = resolve3(root);
2364
2431
  const assertUnderRoot = (target) => {
2365
- const r = resolve2(target);
2432
+ const r = resolve3(target);
2366
2433
  if (r !== rootResolved && !r.startsWith(rootResolved + sep2)) {
2367
2434
  throw new Error(`path escapes state root: ${target}`);
2368
2435
  }
2369
2436
  return target;
2370
2437
  };
2371
- const projDir = (p) => assertUnderRoot(join7(root, safeSegment2("project", p)));
2372
- const itemFile = (p, id) => assertUnderRoot(join7(projDir(p), `${safeSegment2("id", id)}.json`));
2438
+ const projDir = (p) => assertUnderRoot(join8(root, safeSegment2("project", p)));
2439
+ const itemFile = (p, id) => assertUnderRoot(join8(projDir(p), `${safeSegment2("id", id)}.json`));
2373
2440
  return {
2374
2441
  put(item) {
2375
- mkdirSync3(projDir(item.project), { recursive: true });
2442
+ mkdirSync4(projDir(item.project), { recursive: true });
2376
2443
  const dest = itemFile(item.project, item.id);
2377
2444
  const tmp = `${dest}.tmp`;
2378
- writeFileSync4(tmp, JSON.stringify(item, null, 2));
2445
+ writeFileSync5(tmp, JSON.stringify(item, null, 2));
2379
2446
  renameSync2(tmp, dest);
2380
2447
  },
2381
2448
  get(project, id) {
2382
2449
  const f = itemFile(project, id);
2383
- if (!existsSync7(f))
2450
+ if (!existsSync8(f))
2384
2451
  return void 0;
2385
2452
  try {
2386
2453
  return JSON.parse(readFileSync5(f, "utf-8"));
@@ -2390,22 +2457,22 @@ function createWorkStore(root = defaultWorkRoot()) {
2390
2457
  },
2391
2458
  list(project) {
2392
2459
  const d = projDir(project);
2393
- if (!existsSync7(d))
2460
+ if (!existsSync8(d))
2394
2461
  return [];
2395
- return readdirSync2(d).filter((n) => n.endsWith(".json") && !n.endsWith(".json.tmp")).map((n) => {
2462
+ return readdirSync3(d).filter((n) => n.endsWith(".json") && !n.endsWith(".json.tmp")).map((n) => {
2396
2463
  try {
2397
- return JSON.parse(readFileSync5(join7(d, n), "utf-8"));
2464
+ return JSON.parse(readFileSync5(join8(d, n), "utf-8"));
2398
2465
  } catch {
2399
2466
  return void 0;
2400
2467
  }
2401
2468
  }).filter((r) => r !== void 0);
2402
2469
  },
2403
2470
  listAll() {
2404
- if (!existsSync7(root))
2471
+ if (!existsSync8(root))
2405
2472
  return [];
2406
- return readdirSync2(root).filter((p) => {
2473
+ return readdirSync3(root).filter((p) => {
2407
2474
  try {
2408
- return statSync2(join7(root, p)).isDirectory();
2475
+ return statSync2(join8(root, p)).isDirectory();
2409
2476
  } catch {
2410
2477
  return false;
2411
2478
  }
@@ -2413,7 +2480,7 @@ function createWorkStore(root = defaultWorkRoot()) {
2413
2480
  },
2414
2481
  delete(project, id) {
2415
2482
  const f = itemFile(project, id);
2416
- if (existsSync7(f))
2483
+ if (existsSync8(f))
2417
2484
  rmSync4(f);
2418
2485
  }
2419
2486
  };
@@ -2539,16 +2606,16 @@ var init_snapshot = __esm({
2539
2606
 
2540
2607
  // packages/core/dist/launchd.js
2541
2608
  import { execFileSync as execFileSync3 } from "child_process";
2542
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync6, existsSync as existsSync8, openSync, writeSync, closeSync, unlinkSync as unlinkSync2, constants } from "fs";
2609
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, readFileSync as readFileSync6, existsSync as existsSync9, openSync, writeSync, closeSync, unlinkSync as unlinkSync2, constants } from "fs";
2543
2610
  import { homedir as homedir5 } from "os";
2544
- import { dirname as dirname2, join as join8 } from "path";
2611
+ import { dirname as dirname3, join as join9 } from "path";
2545
2612
  import { fileURLToPath } from "url";
2546
2613
  function plistPath() {
2547
- return join8(homedir5(), "Library", "LaunchAgents", `${LABEL}.plist`);
2614
+ return join9(homedir5(), "Library", "LaunchAgents", `${LABEL}.plist`);
2548
2615
  }
2549
2616
  function daemonEntryPath() {
2550
- const p = join8(dirname2(fileURLToPath(import.meta.url)), "squadrantd.js");
2551
- if (!existsSync8(p)) {
2617
+ const p = join9(dirname3(fileURLToPath(import.meta.url)), "squadrantd.js");
2618
+ if (!existsSync9(p)) {
2552
2619
  throw new Error(`daemonEntryPath: compiled entry not found at '${p}'; run 'npm run build' \u2014 a src-tree or missing path in the launchd plist causes a MODULE_NOT_FOUND crash-loop (#259)`);
2553
2620
  }
2554
2621
  return p;
@@ -2598,10 +2665,10 @@ function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
2598
2665
  isUpgrade: isVersionUpgrade(parsed.daemonEntry, thisEntry)
2599
2666
  };
2600
2667
  }
2601
- function sanitizePathForPlist(path43) {
2668
+ function sanitizePathForPlist(path44) {
2602
2669
  const seen = /* @__PURE__ */ new Set();
2603
2670
  const stable = [];
2604
- for (const p of path43.split(":")) {
2671
+ for (const p of path44.split(":")) {
2605
2672
  if (!p)
2606
2673
  continue;
2607
2674
  if (p.includes("/.claude/plugins/"))
@@ -2624,7 +2691,7 @@ function resolveAgentBinDirs() {
2624
2691
  const out = execFileSync3("which", [bin], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
2625
2692
  const resolved = out.trim();
2626
2693
  if (resolved)
2627
- dirs.push(dirname2(resolved));
2694
+ dirs.push(dirname3(resolved));
2628
2695
  } catch {
2629
2696
  }
2630
2697
  }
@@ -2640,7 +2707,7 @@ function buildDaemonPath(shellPath) {
2640
2707
  return sanitizePathForPlist([...resolveAgentBinDirs(), shellPath].join(":"));
2641
2708
  }
2642
2709
  function renderPlist(nodeBin, daemonEntry, pathEnv = "") {
2643
- const logPath2 = join8(homedir5(), ".config", "squadrant", "squadrantd.log");
2710
+ const logPath2 = daemonLogPath();
2644
2711
  return `<?xml version="1.0" encoding="UTF-8"?>
2645
2712
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2646
2713
  <plist version="1.0">
@@ -2669,11 +2736,11 @@ function _resetRestartInFlightForTest() {
2669
2736
  restartInFlight = false;
2670
2737
  }
2671
2738
  function daemonLockPath() {
2672
- return join8(homedir5(), ".config", "squadrant", "daemon.lock");
2739
+ return join9(homedir5(), ".config", "squadrant", "daemon.lock");
2673
2740
  }
2674
2741
  function tryAcquireDaemonLock() {
2675
2742
  const lp = daemonLockPath();
2676
- if (existsSync8(lp)) {
2743
+ if (existsSync9(lp)) {
2677
2744
  try {
2678
2745
  const pid = parseInt(readFileSync6(lp, "utf-8").trim(), 10);
2679
2746
  if (!Number.isFinite(pid) || pid <= 0) {
@@ -2712,19 +2779,20 @@ function computeDaemonDrift(nodeBin) {
2712
2779
  const p = plistPath();
2713
2780
  const entry = daemonEntryPath();
2714
2781
  const desired = renderPlist(nodeBin, entry, buildDaemonPath(process.env.PATH ?? ""));
2715
- const current = existsSync8(p) ? readFileSync6(p, "utf-8") : null;
2782
+ const current = existsSync9(p) ? readFileSync6(p, "utf-8") : null;
2716
2783
  const uid = process.getuid?.() ?? 0;
2717
2784
  const target = `gui/${uid}/${LABEL}`;
2718
2785
  const changed = current !== desired;
2719
2786
  const programChanged = current !== null && changed && !current.includes(programArgsBlock(nodeBin, entry));
2720
2787
  const parsedCurrent = current !== null ? parseProgramArgs(current) : null;
2721
- const foreignInstall = detectForeignInstall(parsedCurrent, entry, parsedCurrent !== null && existsSync8(parsedCurrent.daemonEntry));
2788
+ const foreignInstall = detectForeignInstall(parsedCurrent, entry, parsedCurrent !== null && existsSync9(parsedCurrent.daemonEntry));
2722
2789
  return { plistPath: p, target, desired, current, changed, programChanged, foreignInstall };
2723
2790
  }
2724
2791
  function reconcilePlistAndService(drift) {
2725
2792
  if (drift.changed) {
2726
- mkdirSync4(dirname2(drift.plistPath), { recursive: true });
2727
- writeFileSync5(drift.plistPath, drift.desired);
2793
+ mkdirSync5(dirname3(drift.plistPath), { recursive: true });
2794
+ mkdirSync5(logsRoot(), { recursive: true });
2795
+ writeFileSync6(drift.plistPath, drift.desired);
2728
2796
  }
2729
2797
  if (drift.programChanged) {
2730
2798
  try {
@@ -2742,6 +2810,17 @@ function applyDaemonDrift(drift) {
2742
2810
  reconcilePlistAndService(drift);
2743
2811
  execFileSync3("launchctl", ["kickstart", drift.target], { stdio: "ignore" });
2744
2812
  }
2813
+ function parseLaunchctlStderrPath(printOutput) {
2814
+ const m = printOutput.match(/^\s*stderr path = (.+)$/m);
2815
+ return m ? m[1].trim() : null;
2816
+ }
2817
+ function loadedDaemonLogPath(target) {
2818
+ try {
2819
+ return parseLaunchctlStderrPath(execFileSync3("launchctl", ["print", target], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }));
2820
+ } catch {
2821
+ return null;
2822
+ }
2823
+ }
2745
2824
  function getDaemonPid(target) {
2746
2825
  try {
2747
2826
  const out = execFileSync3("launchctl", ["print", target], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
@@ -2856,7 +2935,9 @@ function reregisterDaemon(nodeBin = process.execPath, kickstartOpts = {}) {
2856
2935
  try {
2857
2936
  const drift = computeDaemonDrift(nodeBin);
2858
2937
  const pidBeforeReconcile = getDaemonPid(drift.target);
2859
- reconcilePlistAndService(drift);
2938
+ const loadedLog = loadedDaemonLogPath(drift.target);
2939
+ const logMoved = loadedLog !== null && loadedLog !== daemonLogPath();
2940
+ reconcilePlistAndService({ ...drift, programChanged: drift.programChanged || logMoved });
2860
2941
  const result = forceKickstartAndVerify(drift.target, { ...kickstartOpts, pidBefore: pidBeforeReconcile });
2861
2942
  if (!result.restarted) {
2862
2943
  throw new Error(`daemon did not restart (pid before=${result.pidBefore ?? "none"}, after=${result.pidAfter ?? "none"}) \u2014 \`launchctl kickstart -k ${drift.target}\` ran but the pid never changed`);
@@ -2869,6 +2950,7 @@ function reregisterDaemon(nodeBin = process.execPath, kickstartOpts = {}) {
2869
2950
  var LABEL, AGENT_BINS, restartInFlight, OPERATOR_INITIATED_COMMANDS, READ_ONLY_CREW_SUBCOMMANDS, READ_ONLY_TOP_LEVEL_COMMANDS;
2870
2951
  var init_launchd = __esm({
2871
2952
  "packages/core/dist/launchd.js"() {
2953
+ init_dist();
2872
2954
  LABEL = "com.squadrant.daemon";
2873
2955
  AGENT_BINS = ["cmux", "claude", "opencode", "codex", "gemini", "node"];
2874
2956
  restartInFlight = false;
@@ -3087,7 +3169,7 @@ var init_gate = __esm({
3087
3169
  });
3088
3170
 
3089
3171
  // packages/core/dist/daemon/liveness-registry.js
3090
- import { writeFileSync as writeFileSync6, readFileSync as readFileSync7, renameSync as renameSync3 } from "fs";
3172
+ import { writeFileSync as writeFileSync7, readFileSync as readFileSync7, renameSync as renameSync3 } from "fs";
3091
3173
  var LivenessRegistry;
3092
3174
  var init_liveness_registry = __esm({
3093
3175
  "packages/core/dist/daemon/liveness-registry.js"() {
@@ -3107,7 +3189,7 @@ var init_liveness_registry = __esm({
3107
3189
  }
3108
3190
  });
3109
3191
  this.writeFile = opts.writeFile ?? ((p, c) => {
3110
- writeFileSync6(`${p}.tmp`, c);
3192
+ writeFileSync7(`${p}.tmp`, c);
3111
3193
  renameSync3(`${p}.tmp`, p);
3112
3194
  });
3113
3195
  }
@@ -3157,10 +3239,9 @@ var init_liveness_registry = __esm({
3157
3239
  });
3158
3240
 
3159
3241
  // packages/core/dist/daemon/context.js
3160
- import { homedir as homedir6 } from "os";
3161
- import { join as join9 } from "path";
3242
+ import { join as join10 } from "path";
3162
3243
  import { spawn as realSpawn } from "child_process";
3163
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
3244
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6 } from "fs";
3164
3245
  function defaultIsPidAlive(pid) {
3165
3246
  try {
3166
3247
  process.kill(pid, 0);
@@ -3170,27 +3251,27 @@ function defaultIsPidAlive(pid) {
3170
3251
  }
3171
3252
  }
3172
3253
  function buildContext(opts) {
3173
- const stateRoot = opts.stateRoot ?? join9(homedir6(), ".config", "squadrant", "state");
3254
+ const stateRoot2 = opts.stateRoot ?? stateRoot();
3174
3255
  const sockPath = opts.sockPath ?? DAEMON_SOCK_PATH;
3175
- const store = createStore(stateRoot);
3256
+ const store = createStore(stateRoot2);
3176
3257
  const bootedAt = Date.now();
3177
3258
  const config = loadConfig();
3178
3259
  const taskTimeoutMs = config.defaults.taskTimeoutMs;
3179
3260
  const takeoverNudgeHours = config.defaults.takeoverNudgeHours;
3180
3261
  const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;
3181
3262
  const spawn2 = opts.spawn ?? realSpawn;
3182
- const resultsDir = join9(stateRoot, "_results");
3183
- mkdirSync5(resultsDir, { recursive: true });
3263
+ const resultsDir = join10(stateRoot2, "_results");
3264
+ mkdirSync6(resultsDir, { recursive: true });
3184
3265
  const writeResult = (id, payload) => {
3185
- const p = join9(resultsDir, `${id}.txt`);
3186
- writeFileSync7(p, payload);
3266
+ const p = join10(resultsDir, `${id}.txt`);
3267
+ writeFileSync8(p, payload);
3187
3268
  return p;
3188
3269
  };
3189
3270
  const log = (m) => process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} ${m}
3190
3271
  `);
3191
3272
  return {
3192
3273
  opts,
3193
- stateRoot,
3274
+ stateRoot: stateRoot2,
3194
3275
  sockPath,
3195
3276
  store,
3196
3277
  bootedAt,
@@ -3206,7 +3287,7 @@ function buildContext(opts) {
3206
3287
  inFlightHeadlessIds: /* @__PURE__ */ new Set(),
3207
3288
  activeHeadlessKills: /* @__PURE__ */ new Set(),
3208
3289
  livenessRegistry: (() => {
3209
- const r = new LivenessRegistry({ path: join9(stateRoot, "liveness.json") });
3290
+ const r = new LivenessRegistry({ path: join10(stateRoot2, "liveness.json") });
3210
3291
  r.load();
3211
3292
  return r;
3212
3293
  })(),
@@ -3874,8 +3955,8 @@ var init_crew_routing = __esm({
3874
3955
 
3875
3956
  // packages/core/dist/permission-gate.js
3876
3957
  import { createHash } from "crypto";
3877
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3 } from "fs";
3878
- import { dirname as dirname3, join as join10 } from "path";
3958
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3 } from "fs";
3959
+ import { dirname as dirname4, join as join11 } from "path";
3879
3960
  function isGateSession(env) {
3880
3961
  return Boolean(env.SQUADRANT_CREW_TASK_ID) || env[SIDE_SESSION_ENV] === "1" || env.SQUADRANT_ROLE === "captain";
3881
3962
  }
@@ -4097,7 +4178,7 @@ async function callClassifier(o) {
4097
4178
  }
4098
4179
  }
4099
4180
  function defaultGateCachePath() {
4100
- return join10(CONFIG_DIR, "state", "gate-cache.json");
4181
+ return join11(CONFIG_DIR, "state", "gate-cache.json");
4101
4182
  }
4102
4183
  function gateCacheKey(toolName, cwd, toolPayload) {
4103
4184
  return createHash("sha256").update(`${toolName}
@@ -4261,8 +4342,8 @@ var init_permission_gate = __esm({
4261
4342
  const next = Object.fromEntries(entries);
4262
4343
  const tmp = `${this.path}.${process.pid}.${Date.now()}.tmp`;
4263
4344
  try {
4264
- mkdirSync6(dirname3(this.path), { recursive: true });
4265
- writeFileSync8(tmp, JSON.stringify(next), "utf-8");
4345
+ mkdirSync7(dirname4(this.path), { recursive: true });
4346
+ writeFileSync9(tmp, JSON.stringify(next), "utf-8");
4266
4347
  renameSync4(tmp, this.path);
4267
4348
  } catch {
4268
4349
  try {
@@ -4356,14 +4437,14 @@ var init_auto_gate = __esm({
4356
4437
  });
4357
4438
 
4358
4439
  // packages/core/dist/first-turn-spill.js
4359
- import fs9 from "fs";
4360
- import os4 from "os";
4361
- import path10 from "path";
4440
+ import fs10 from "fs";
4441
+ import os5 from "os";
4442
+ import path11 from "path";
4362
4443
  function spillOversizedFirstTurn(text, id) {
4363
4444
  if (Buffer.byteLength(text, "utf8") <= FIRST_TURN_INLINE_MAX_BYTES)
4364
4445
  return text;
4365
- const spillFile = path10.join(os4.tmpdir(), `squadrant-task-${id}.md`);
4366
- fs9.writeFileSync(spillFile, text, "utf8");
4446
+ const spillFile = path11.join(os5.tmpdir(), `squadrant-task-${id}.md`);
4447
+ fs10.writeFileSync(spillFile, text, "utf8");
4367
4448
  return `Full task is at ${spillFile} \u2014 cat it and follow it exactly.`;
4368
4449
  }
4369
4450
  var FIRST_TURN_INLINE_MAX_BYTES;
@@ -4435,8 +4516,8 @@ import { exec as nodeExec } from "child_process";
4435
4516
  async function reapCrewChildren(taskId, graceMs = 2e3, execFn = nodeExec) {
4436
4517
  const marker = `SQUADRANT_CREW_TASK_ID=${taskId}`;
4437
4518
  try {
4438
- const stdout = await new Promise((resolve4, reject) => {
4439
- execFn("ps auxE", { maxBuffer: 64 * 1024 * 1024 }, (err, out) => err ? reject(err) : resolve4(out));
4519
+ const stdout = await new Promise((resolve5, reject) => {
4520
+ execFn("ps auxE", { maxBuffer: 64 * 1024 * 1024 }, (err, out) => err ? reject(err) : resolve5(out));
4440
4521
  });
4441
4522
  const pids = [];
4442
4523
  for (const line2 of stdout.split("\n").slice(1)) {
@@ -4470,14 +4551,14 @@ var init_crew_lifecycle = __esm({
4470
4551
  });
4471
4552
 
4472
4553
  // packages/core/dist/crew-spawn.js
4473
- import fs10 from "fs";
4474
- import os5 from "os";
4475
- import path11 from "path";
4554
+ import fs11 from "fs";
4555
+ import os6 from "os";
4556
+ import path12 from "path";
4476
4557
  import { randomUUID as randomUUID3 } from "crypto";
4477
4558
  function ensureSocksDir(dir = CC_SOCKS_DIR) {
4478
- fs10.mkdirSync(dir, { recursive: true, mode: 448 });
4479
- if ((fs10.statSync(dir).mode & 511) !== 448)
4480
- fs10.chmodSync(dir, 448);
4559
+ fs11.mkdirSync(dir, { recursive: true, mode: 448 });
4560
+ if ((fs11.statSync(dir).mode & 511) !== 448)
4561
+ fs11.chmodSync(dir, 448);
4481
4562
  }
4482
4563
  async function pollFirstTurnConfirmedAt(getTaskRecord, project, id, scrapeSettled, cancel) {
4483
4564
  let scrapeSettledAt;
@@ -4499,14 +4580,14 @@ async function pollFirstTurnConfirmedAt(getTaskRecord, project, id, scrapeSettle
4499
4580
  }
4500
4581
  }
4501
4582
  function firstTrueOrBothFalse(a, b, deadlineMs) {
4502
- return new Promise((resolve4) => {
4583
+ return new Promise((resolve5) => {
4503
4584
  let done = false;
4504
4585
  const finish = (ok2) => {
4505
4586
  if (done)
4506
4587
  return;
4507
4588
  done = true;
4508
4589
  clearTimeout(timer);
4509
- resolve4(ok2);
4590
+ resolve5(ok2);
4510
4591
  };
4511
4592
  const timer = setTimeout(() => finish(false), deadlineMs);
4512
4593
  let settledFalseCount = 0;
@@ -4610,9 +4691,9 @@ async function runCrewSpawn(input, config, deps) {
4610
4691
  }) : proj.path;
4611
4692
  let firstTurnTask = input.task;
4612
4693
  if (input.taskFile && input.taskFile !== "-" && !input.shared) {
4613
- const absTaskFile = path11.resolve(input.taskFile);
4614
- const basename = path11.basename(absTaskFile);
4615
- fs10.copyFileSync(absTaskFile, path11.join(spawnCwd, basename));
4694
+ const absTaskFile = path12.resolve(input.taskFile);
4695
+ const basename = path12.basename(absTaskFile);
4696
+ fs11.copyFileSync(absTaskFile, path12.join(spawnCwd, basename));
4616
4697
  firstTurnTask = `Read ./${basename} to get your task brief, then execute it.`;
4617
4698
  }
4618
4699
  const agentName = requestedAgent;
@@ -4626,8 +4707,8 @@ async function runCrewSpawn(input, config, deps) {
4626
4707
  assertBackendUsable({ backend, agent: agent.name, router: config.defaults.router });
4627
4708
  deps.onBackendResolved?.({ backend });
4628
4709
  if (agentName === "codex") {
4629
- const codexRoleFile = path11.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);
4630
- const roleInstructions = fs10.existsSync(codexRoleFile) ? fs10.readFileSync(codexRoleFile, "utf8") : void 0;
4710
+ const codexRoleFile = path12.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);
4711
+ const roleInstructions = fs11.existsSync(codexRoleFile) ? fs11.readFileSync(codexRoleFile, "utf8") : void 0;
4631
4712
  return runCodexInteractiveSpawn({
4632
4713
  project: input.project,
4633
4714
  task: input.task,
@@ -4643,7 +4724,7 @@ async function runCrewSpawn(input, config, deps) {
4643
4724
  sendCodexFirstTurn: deps.sendCodexFirstTurn
4644
4725
  });
4645
4726
  }
4646
- const promptFile = path11.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);
4727
+ const promptFile = path12.join(TEMPLATES_DIR, `crew.${agent.templateSuffix}.md`);
4647
4728
  const interactive = agent.name === "claude" || agent.name === "opencode";
4648
4729
  const crewRole = config.defaults.roles?.crew;
4649
4730
  const configModel = crewRole && crewRole.agent === agent.name ? crewRole.model : void 0;
@@ -4669,7 +4750,7 @@ async function runCrewSpawn(input, config, deps) {
4669
4750
  }
4670
4751
  }
4671
4752
  ensureSocksDir();
4672
- const messagingSocketPath = path11.join(CC_SOCKS_DIR, `squadrant-${randomUUID3()}.sock`);
4753
+ const messagingSocketPath = path12.join(CC_SOCKS_DIR, `squadrant-${randomUUID3()}.sock`);
4673
4754
  const rec = await deps.dispatchCrew({
4674
4755
  provider: "claude",
4675
4756
  mode: "interactive",
@@ -4680,7 +4761,7 @@ async function runCrewSpawn(input, config, deps) {
4680
4761
  messagingSocketPath
4681
4762
  });
4682
4763
  const routerSettingsPath = Object.keys(routerEnv).length > 0 ? deps.writeRouterSettings({
4683
- stateRoot: STATE_ROOT,
4764
+ stateRoot: stateRoot(),
4684
4765
  project: input.project,
4685
4766
  taskId: rec.id,
4686
4767
  env: mergeClaudeEnvRouterSettings(routerEnv, config.defaults.claudeEnv)
@@ -4777,7 +4858,7 @@ ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen) : Promise.r
4777
4858
  `);
4778
4859
  }
4779
4860
  const opencodeConfigPath = deps.writeOpencodeConfig({
4780
- stateRoot: STATE_ROOT,
4861
+ stateRoot: stateRoot(),
4781
4862
  project: input.project,
4782
4863
  taskId: rec.id,
4783
4864
  // CP3 opt-in: --approval gates bash so the captain approves shell commands.
@@ -4947,7 +5028,7 @@ function buildRecoveryHint(sessId, provider, worktreeCwd) {
4947
5028
  return "";
4948
5029
  if (provider === "claude") {
4949
5030
  const escaped = worktreeCwd.replace(/[^a-zA-Z0-9]/g, "-");
4950
- const transcriptPath = path11.join(os5.homedir(), ".claude", "projects", escaped, `${sessId}.jsonl`);
5031
+ const transcriptPath = path12.join(os6.homedir(), ".claude", "projects", escaped, `${sessId}.jsonl`);
4951
5032
  return `
4952
5033
  transcript: ${transcriptPath}
4953
5034
  resume: claude --resume ${sessId} (run from the worktree path above)
@@ -5042,7 +5123,7 @@ async function runCrewList(project, runtime, workspaceId) {
5042
5123
  surfaceId: c.surfaceId
5043
5124
  }));
5044
5125
  }
5045
- var CC_SOCKS_DIR, TEMPLATES_DIR, STATE_ROOT, FIRST_TURN_HOOK_CONFIRM_GRACE_MS, FIRST_TURN_HOOK_CONFIRM_MAX_MS, FIRST_TURN_HOOK_POLL_INTERVAL_MS, CLOSE_LOOKUP_RETRIES, CLOSE_LOOKUP_RETRY_DELAY_MS;
5126
+ var CC_SOCKS_DIR, TEMPLATES_DIR, FIRST_TURN_HOOK_CONFIRM_GRACE_MS, FIRST_TURN_HOOK_CONFIRM_MAX_MS, FIRST_TURN_HOOK_POLL_INTERVAL_MS, CLOSE_LOOKUP_RETRIES, CLOSE_LOOKUP_RETRY_DELAY_MS;
5046
5127
  var init_crew_spawn = __esm({
5047
5128
  "packages/core/dist/crew-spawn.js"() {
5048
5129
  init_control_channel();
@@ -5056,8 +5137,7 @@ var init_crew_spawn = __esm({
5056
5137
  init_crew_protocol();
5057
5138
  init_crew_lifecycle();
5058
5139
  CC_SOCKS_DIR = "/tmp/cc-socks";
5059
- TEMPLATES_DIR = path11.join(os5.homedir(), ".config", "squadrant", "templates");
5060
- STATE_ROOT = path11.join(os5.homedir(), ".config", "squadrant", "state");
5140
+ TEMPLATES_DIR = path12.join(os6.homedir(), ".config", "squadrant", "templates");
5061
5141
  FIRST_TURN_HOOK_CONFIRM_GRACE_MS = 15e3;
5062
5142
  FIRST_TURN_HOOK_CONFIRM_MAX_MS = 18e4;
5063
5143
  FIRST_TURN_HOOK_POLL_INTERVAL_MS = 2e3;
@@ -5067,12 +5147,12 @@ var init_crew_spawn = __esm({
5067
5147
  });
5068
5148
 
5069
5149
  // packages/core/dist/captain-channel.js
5070
- import { join as join11 } from "path";
5150
+ import { join as join12 } from "path";
5071
5151
  function captainSocketPath(project, socksDir = CC_SOCKS_DIR) {
5072
5152
  if (!/^[A-Za-z0-9._-]+$/.test(project)) {
5073
5153
  throw new Error(`captain-channel: project name '${project}' is not a safe socket filename`);
5074
5154
  }
5075
- return join11(socksDir, `squadrant-captain-${project}.sock`);
5155
+ return join12(socksDir, `squadrant-captain-${project}.sock`);
5076
5156
  }
5077
5157
  async function deliverToCaptain(project, text, deps) {
5078
5158
  if (deps.mode === "off")
@@ -5102,23 +5182,23 @@ var init_captain_channel = __esm({
5102
5182
  });
5103
5183
 
5104
5184
  // packages/core/dist/captain-record.js
5105
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync9, realpathSync, writeFileSync as writeFileSync9 } from "fs";
5106
- import { dirname as dirname4, join as join12 } from "path";
5107
- function captainRecordPath(stateRoot, project) {
5108
- return join12(stateRoot, project, "captain.json");
5185
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync9, realpathSync, writeFileSync as writeFileSync10 } from "fs";
5186
+ import { dirname as dirname5, join as join13 } from "path";
5187
+ function captainRecordPath(stateRoot2, project) {
5188
+ return join13(stateRoot2, project, "captain.json");
5109
5189
  }
5110
- function readCaptainAddress(stateRoot, project) {
5190
+ function readCaptainAddress(stateRoot2, project) {
5111
5191
  try {
5112
- const parsed = JSON.parse(readFileSync9(captainRecordPath(stateRoot, project), "utf-8"));
5192
+ const parsed = JSON.parse(readFileSync9(captainRecordPath(stateRoot2, project), "utf-8"));
5113
5193
  return parsed && typeof parsed.agent === "string" ? parsed : null;
5114
5194
  } catch {
5115
5195
  return null;
5116
5196
  }
5117
5197
  }
5118
- function writeCaptainAddress(stateRoot, project, addr) {
5119
- const p = captainRecordPath(stateRoot, project);
5120
- mkdirSync7(dirname4(p), { recursive: true });
5121
- writeFileSync9(p, JSON.stringify(addr, null, 2) + "\n");
5198
+ function writeCaptainAddress(stateRoot2, project, addr) {
5199
+ const p = captainRecordPath(stateRoot2, project);
5200
+ mkdirSync8(dirname5(p), { recursive: true });
5201
+ writeFileSync10(p, JSON.stringify(addr, null, 2) + "\n");
5122
5202
  }
5123
5203
  function realpathOrSelf(p) {
5124
5204
  try {
@@ -5141,11 +5221,11 @@ var init_captain_record = __esm({
5141
5221
  // packages/core/dist/opencode-session.js
5142
5222
  import { execFileSync as execFileSync4 } from "child_process";
5143
5223
  async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
5144
- for (const path43 of ["/session", "/api/session"]) {
5224
+ for (const path44 of ["/session", "/api/session"]) {
5145
5225
  const ac = new AbortController();
5146
5226
  const t = setTimeout(() => ac.abort(), timeoutMs);
5147
5227
  try {
5148
- const res = await fetchImpl(`http://127.0.0.1:${port}${path43}`, { signal: ac.signal });
5228
+ const res = await fetchImpl(`http://127.0.0.1:${port}${path44}`, { signal: ac.signal });
5149
5229
  if (!res.ok)
5150
5230
  continue;
5151
5231
  const rows = await res.json();
@@ -5276,19 +5356,19 @@ async function reresolveOpencodeAddress(rec) {
5276
5356
  return null;
5277
5357
  return { port, sessionId };
5278
5358
  }
5279
- async function healStaleOpencodeAddress(stateRoot, project, log, logPrefix) {
5280
- const rec = readCaptainAddress(stateRoot, project);
5359
+ async function healStaleOpencodeAddress(stateRoot2, project, log, logPrefix) {
5360
+ const rec = readCaptainAddress(stateRoot2, project);
5281
5361
  if (!rec)
5282
5362
  return false;
5283
5363
  const resolved = await reresolveOpencodeAddress(rec);
5284
5364
  if (!resolved)
5285
5365
  return false;
5286
- const current = readCaptainAddress(stateRoot, project);
5366
+ const current = readCaptainAddress(stateRoot2, project);
5287
5367
  if (!current || current.launchedAt !== rec.launchedAt) {
5288
5368
  log(`captain-channel ${project}: skipped stale-address heal \u2014 a newer launch record won the race`);
5289
5369
  return false;
5290
5370
  }
5291
- writeCaptainAddress(stateRoot, project, { ...current, port: resolved.port, sessionId: resolved.sessionId });
5371
+ writeCaptainAddress(stateRoot2, project, { ...current, port: resolved.port, sessionId: resolved.sessionId });
5292
5372
  log(`captain-channel ${project}: ${logPrefix} \u2192 port ${resolved.port}`);
5293
5373
  return true;
5294
5374
  }
@@ -5384,7 +5464,7 @@ async function runLivenessTick(deps) {
5384
5464
  }
5385
5465
  }
5386
5466
  function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5387
- const { stateRoot, store, log, livenessRegistry, isPidAlive, opts, telegramBridge } = ctx;
5467
+ const { stateRoot: stateRoot2, store, log, livenessRegistry, isPidAlive, opts, telegramBridge } = ctx;
5388
5468
  const surfaceProbe = isSurfaceAlive ?? (async () => "unknown");
5389
5469
  const notifyFault = ctx.notifyFault ?? (() => {
5390
5470
  });
@@ -5395,7 +5475,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5395
5475
  }
5396
5476
  try {
5397
5477
  await appendToMailbox({
5398
- stateRoot,
5478
+ stateRoot: stateRoot2,
5399
5479
  project: args.project,
5400
5480
  taskRecord: args.record,
5401
5481
  event: args.event,
@@ -5474,7 +5554,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5474
5554
  surface = await resolveCaptainSurface();
5475
5555
  if (!surface)
5476
5556
  continue;
5477
- const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER });
5557
+ const cursor = await readCursor({ stateRoot: stateRoot2, project, subscriber: CURSOR_SUBSCRIBER });
5478
5558
  const lastAcked = cursor?.lastAckedSeq ?? 0;
5479
5559
  let d = deliveries.get(project);
5480
5560
  if (!d) {
@@ -5485,7 +5565,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5485
5565
  deliveries.set(project, d);
5486
5566
  }
5487
5567
  const pending = [];
5488
- for await (const entry of readFromCursor({ stateRoot, project, fromSeq: lastAcked + 1 }))
5568
+ for await (const entry of readFromCursor({ stateRoot: stateRoot2, project, fromSeq: lastAcked + 1 }))
5489
5569
  pending.push(entry);
5490
5570
  const decisions = coalesceBacklog(pending, {
5491
5571
  now: Date.now(),
@@ -5498,7 +5578,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5498
5578
  const isExemptMessage = entry.kind === "captain.message" && entry.payload?.source !== "daemon";
5499
5579
  if (!isExemptMessage) {
5500
5580
  log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-skipped`);
5501
- await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
5581
+ await writeCursor({ stateRoot: stateRoot2, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
5502
5582
  continue;
5503
5583
  }
5504
5584
  if (logStale)
@@ -5511,7 +5591,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5511
5591
  const decision = decisions[i];
5512
5592
  if (decision.action === "skip") {
5513
5593
  log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=coalesced reason=${decision.reason}`);
5514
- await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
5594
+ await writeCursor({ stateRoot: stateRoot2, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
5515
5595
  continue;
5516
5596
  }
5517
5597
  const result = await d.deliver(decision.entry, async (text, sendOpts) => {
@@ -5527,7 +5607,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5527
5607
  log(`captain-channel ${project}: threw, falling back to pane \u2014 ${e.message}`);
5528
5608
  }
5529
5609
  if (agent === "opencode" && mode !== "off") {
5530
- const healed = await healStaleOpencodeAddress(stateRoot, project, log, "re-resolved opencode address");
5610
+ const healed = await healStaleOpencodeAddress(stateRoot2, project, log, "re-resolved opencode address");
5531
5611
  if (healed) {
5532
5612
  try {
5533
5613
  const retry = await deliverToCaptain(project, text, { channel: picked, mode, log });
@@ -5564,7 +5644,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5564
5644
  });
5565
5645
  if ("delivered" in result) {
5566
5646
  log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=delivered`);
5567
- await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
5647
+ await writeCursor({ stateRoot: stateRoot2, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
5568
5648
  lastDeferred.delete(project);
5569
5649
  projectBackoff.delete(project);
5570
5650
  } else {
@@ -5591,7 +5671,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
5591
5671
  log(`delivery stuck project=${project} deferCount=${maxDeferCount} reason=${reason ?? "unknown"}`);
5592
5672
  const text = STUCK_ALERT_TEXT[reason ?? "unknown"](maxDeferCount);
5593
5673
  try {
5594
- await appendCaptainMessage({ stateRoot, project, text, source: "daemon" });
5674
+ await appendCaptainMessage({ stateRoot: stateRoot2, project, text, source: "daemon" });
5595
5675
  } catch (e) {
5596
5676
  log(`delivery stuck alert failed project=${project}: ${e.message}`);
5597
5677
  }
@@ -5766,21 +5846,21 @@ var init_server = __esm({
5766
5846
  });
5767
5847
 
5768
5848
  // packages/core/dist/daemon/exit-marker.js
5769
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync9 } from "fs";
5770
- import { join as join13 } from "path";
5771
- function exitMarkerPath(stateRoot) {
5772
- return join13(stateRoot, "exit-marker.json");
5849
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync11, unlinkSync as unlinkSync4, existsSync as existsSync10 } from "fs";
5850
+ import { join as join14 } from "path";
5851
+ function exitMarkerPath(stateRoot2) {
5852
+ return join14(stateRoot2, "exit-marker.json");
5773
5853
  }
5774
- function writeExitMarker(stateRoot, marker, log) {
5854
+ function writeExitMarker(stateRoot2, marker, log) {
5775
5855
  try {
5776
- writeFileSync10(exitMarkerPath(stateRoot), JSON.stringify(marker));
5856
+ writeFileSync11(exitMarkerPath(stateRoot2), JSON.stringify(marker));
5777
5857
  } catch (e) {
5778
5858
  log(`exit marker write failed: ${e.message}`);
5779
5859
  }
5780
5860
  }
5781
- function consumeExitMarker(stateRoot, now = Date.now) {
5782
- const p = exitMarkerPath(stateRoot);
5783
- if (!existsSync9(p))
5861
+ function consumeExitMarker(stateRoot2, now = Date.now) {
5862
+ const p = exitMarkerPath(stateRoot2);
5863
+ if (!existsSync10(p))
5784
5864
  return { marker: null };
5785
5865
  let marker = null;
5786
5866
  try {
@@ -5797,26 +5877,26 @@ function consumeExitMarker(stateRoot, now = Date.now) {
5797
5877
  const gapMs = Math.max(0, now() - new Date(marker.ts).getTime());
5798
5878
  return { marker, gapMs };
5799
5879
  }
5800
- function runningMarkerPath(stateRoot) {
5801
- return join13(stateRoot, "running-marker.json");
5880
+ function runningMarkerPath(stateRoot2) {
5881
+ return join14(stateRoot2, "running-marker.json");
5802
5882
  }
5803
- function writeRunningMarker(stateRoot, marker, log) {
5883
+ function writeRunningMarker(stateRoot2, marker, log) {
5804
5884
  try {
5805
- writeFileSync10(runningMarkerPath(stateRoot), JSON.stringify(marker));
5885
+ writeFileSync11(runningMarkerPath(stateRoot2), JSON.stringify(marker));
5806
5886
  } catch (e) {
5807
5887
  log(`running marker write failed: ${e.message}`);
5808
5888
  }
5809
5889
  }
5810
- function readRunningMarker(stateRoot) {
5890
+ function readRunningMarker(stateRoot2) {
5811
5891
  try {
5812
- return JSON.parse(readFileSync10(runningMarkerPath(stateRoot), "utf-8"));
5892
+ return JSON.parse(readFileSync10(runningMarkerPath(stateRoot2), "utf-8"));
5813
5893
  } catch {
5814
5894
  return null;
5815
5895
  }
5816
5896
  }
5817
- function removeRunningMarker(stateRoot, log) {
5897
+ function removeRunningMarker(stateRoot2, log) {
5818
5898
  try {
5819
- unlinkSync4(runningMarkerPath(stateRoot));
5899
+ unlinkSync4(runningMarkerPath(stateRoot2));
5820
5900
  } catch (e) {
5821
5901
  if (e.code !== "ENOENT")
5822
5902
  log(`running marker remove failed: ${e.message}`);
@@ -5829,8 +5909,8 @@ var init_exit_marker = __esm({
5829
5909
 
5830
5910
  // packages/core/dist/daemon/snapshot-gather.js
5831
5911
  import { fileURLToPath as fileURLToPath2 } from "url";
5832
- import { join as join14 } from "path";
5833
- import { statSync as statSync3, openSync as openSync2, readSync, closeSync as closeSync2, readdirSync as readdirSync3, readFileSync as readFileSync11 } from "fs";
5912
+ import { join as join15 } from "path";
5913
+ import { statSync as statSync3, openSync as openSync2, readSync, closeSync as closeSync2, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "fs";
5834
5914
  function distBuiltAt() {
5835
5915
  try {
5836
5916
  return statSync3(SELF_PATH).mtimeMs;
@@ -5838,10 +5918,10 @@ function distBuiltAt() {
5838
5918
  return 0;
5839
5919
  }
5840
5920
  }
5841
- function gatherLogStats(path43, now, windowMs) {
5921
+ function gatherLogStats(path44, now, windowMs) {
5842
5922
  let sizeBytes = 0;
5843
5923
  try {
5844
- sizeBytes = statSync3(path43).size;
5924
+ sizeBytes = statSync3(path44).size;
5845
5925
  } catch {
5846
5926
  return { errorCount: 0, sizeBytes: 0, windowMs };
5847
5927
  }
@@ -5852,7 +5932,7 @@ function gatherLogStats(path43, now, windowMs) {
5852
5932
  const len = sizeBytes - start;
5853
5933
  let text = "";
5854
5934
  try {
5855
- const fd = openSync2(path43, "r");
5935
+ const fd = openSync2(path44, "r");
5856
5936
  try {
5857
5937
  const buf = Buffer.alloc(len);
5858
5938
  readSync(fd, buf, 0, len, start);
@@ -5878,14 +5958,14 @@ function gatherLogStats(path43, now, windowMs) {
5878
5958
  }
5879
5959
  return { errorCount, sizeBytes, windowMs };
5880
5960
  }
5881
- function gatherStoreStats(store, stateRoot, project) {
5961
+ function gatherStoreStats(store, stateRoot2, project) {
5882
5962
  const byState = {};
5883
5963
  for (const r of store.list(project))
5884
5964
  byState[r.state] = (byState[r.state] ?? 0) + 1;
5885
5965
  let corruptCount = 0;
5886
- const dir = join14(stateRoot, project);
5966
+ const dir = join15(stateRoot2, project);
5887
5967
  try {
5888
- for (const n of readdirSync3(dir)) {
5968
+ for (const n of readdirSync4(dir)) {
5889
5969
  if (n.includes(".corrupt.")) {
5890
5970
  corruptCount++;
5891
5971
  continue;
@@ -5893,7 +5973,7 @@ function gatherStoreStats(store, stateRoot, project) {
5893
5973
  if (!n.endsWith(".json"))
5894
5974
  continue;
5895
5975
  try {
5896
- JSON.parse(readFileSync11(join14(dir, n), "utf-8"));
5976
+ JSON.parse(readFileSync11(join15(dir, n), "utf-8"));
5897
5977
  } catch {
5898
5978
  corruptCount++;
5899
5979
  }
@@ -5906,9 +5986,9 @@ function gatherResults(resultsDir) {
5906
5986
  let fileCount = 0;
5907
5987
  let totalBytes = 0;
5908
5988
  try {
5909
- for (const n of readdirSync3(resultsDir)) {
5989
+ for (const n of readdirSync4(resultsDir)) {
5910
5990
  try {
5911
- const s = statSync3(join14(resultsDir, n));
5991
+ const s = statSync3(join15(resultsDir, n));
5912
5992
  if (s.isFile()) {
5913
5993
  fileCount++;
5914
5994
  totalBytes += s.size;
@@ -5928,10 +6008,10 @@ var init_snapshot_gather = __esm({
5928
6008
  });
5929
6009
 
5930
6010
  // packages/core/dist/daemon/start.js
5931
- import { join as join15, dirname as dirname5 } from "path";
6011
+ import { join as join16 } from "path";
5932
6012
  import { readdir } from "fs/promises";
5933
6013
  function startDaemon(ctx, opts, pkgVersion) {
5934
- const { stateRoot, store, log, isPidAlive, resultsDir, taskTimeoutMs, inFlightHeadlessIds, activeHeadlessKills, broadcast, cancelPromotionsFor } = ctx;
6014
+ const { stateRoot: stateRoot2, store, log, isPidAlive, resultsDir, taskTimeoutMs, inFlightHeadlessIds, activeHeadlessKills, broadcast, cancelPromotionsFor } = ctx;
5935
6015
  const { daemonCmux } = ctx;
5936
6016
  const probes = createProbes(ctx);
5937
6017
  const surfaceProbe = buildSurfaceProbe(ctx, probes, daemonCmux);
@@ -6005,14 +6085,14 @@ function startDaemon(ctx, opts, pkgVersion) {
6005
6085
  return out;
6006
6086
  }
6007
6087
  async function gatherSnapshotInputs(now) {
6008
- const logPath2 = join15(dirname5(stateRoot), "squadrantd.log");
6088
+ const logPath2 = stateRoot2 === stateRoot() ? resolveReadPath(daemonLogPath(), legacyDaemonLogPath()) : join16(stateRoot2, "logs", "squadrantd.log");
6009
6089
  const tier2Projects = opts.registeredProjects ?? Object.keys(loadConfig().projects);
6010
6090
  const projects = await Promise.all(tier2Projects.map(async (project) => {
6011
- const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER2 });
6012
- const storeStats = gatherStoreStats(store, stateRoot, project);
6091
+ const cursor = await readCursor({ stateRoot: stateRoot2, project, subscriber: CURSOR_SUBSCRIBER2 });
6092
+ const storeStats = gatherStoreStats(store, stateRoot2, project);
6013
6093
  return {
6014
6094
  project,
6015
- mailbox: await mailboxStats(stateRoot, project),
6095
+ mailbox: await mailboxStats(stateRoot2, project),
6016
6096
  lastAckedSeq: cursor?.lastAckedSeq ?? 0,
6017
6097
  storeByState: storeStats.byState,
6018
6098
  corruptCount: storeStats.corruptCount,
@@ -6101,18 +6181,18 @@ function startDaemon(ctx, opts, pkgVersion) {
6101
6181
  }
6102
6182
  })();
6103
6183
  const server = createServer2(ctx, { buildHealth, gatherSnapshotInputs, cancelPromotionsFor, broadcast });
6104
- log(`boot pid=${process.pid} version=${pkgVersion} socket=${ctx.sockPath} stateRoot=${stateRoot}`);
6184
+ log(`boot pid=${process.pid} version=${pkgVersion} socket=${ctx.sockPath} stateRoot=${stateRoot2}`);
6105
6185
  const bootTs = (/* @__PURE__ */ new Date()).toISOString();
6106
6186
  {
6107
6187
  const sendDownAlert = (startTs, endTs, minutes, reasonText) => {
6108
6188
  const text = formatDownAlertText({ startTs, endTs, minutes, reasonText });
6109
6189
  const alertProjects = opts.registeredProjects ?? Object.keys(loadConfig().projects);
6110
6190
  for (const project of alertProjects) {
6111
- appendCaptainMessage({ stateRoot, project, text, source: "daemon" }).catch((e) => log(`boot-gap alert failed project=${project}: ${e.message}`));
6191
+ appendCaptainMessage({ stateRoot: stateRoot2, project, text, source: "daemon" }).catch((e) => log(`boot-gap alert failed project=${project}: ${e.message}`));
6112
6192
  }
6113
6193
  };
6114
- const { marker, gapMs } = consumeExitMarker(stateRoot);
6115
- const prevRunning = readRunningMarker(stateRoot);
6194
+ const { marker, gapMs } = consumeExitMarker(stateRoot2);
6195
+ const prevRunning = readRunningMarker(stateRoot2);
6116
6196
  if (marker) {
6117
6197
  log(`previous exit ts=${marker.ts} reason=${marker.reason} gap=${((gapMs ?? 0) / 1e3).toFixed(1)}s`);
6118
6198
  if ((gapMs ?? 0) > 6e4)
@@ -6127,7 +6207,7 @@ function startDaemon(ctx, opts, pkgVersion) {
6127
6207
  } else {
6128
6208
  log("previous exit: none (clean or first boot)");
6129
6209
  }
6130
- writeRunningMarker(stateRoot, { pid: process.pid, bootTs, lastHeartbeatTs: bootTs }, log);
6210
+ writeRunningMarker(stateRoot2, { pid: process.pid, bootTs, lastHeartbeatTs: bootTs }, log);
6131
6211
  }
6132
6212
  let deliveryTick = initialDeliveryTick;
6133
6213
  let probeTick;
@@ -6171,7 +6251,7 @@ function startDaemon(ctx, opts, pkgVersion) {
6171
6251
  let rotationTimer;
6172
6252
  let rotationTick;
6173
6253
  if (rotationInterval > 0) {
6174
- const inboxPath = join15(stateRoot, "inbox");
6254
+ const inboxPath = join16(stateRoot2, "inbox");
6175
6255
  rotationTick = async () => {
6176
6256
  try {
6177
6257
  let entries;
@@ -6182,12 +6262,12 @@ function startDaemon(ctx, opts, pkgVersion) {
6182
6262
  }
6183
6263
  const projects = new Set(entries.filter((e) => e.endsWith(".log")).map((e) => e.slice(0, -".log".length)));
6184
6264
  for (const project of projects)
6185
- await rotateIfNeeded({ stateRoot, project, ...mboxCfg });
6265
+ await rotateIfNeeded({ stateRoot: stateRoot2, project, ...mboxCfg });
6186
6266
  await opts.knowledgeTick?.();
6187
6267
  } catch (e) {
6188
6268
  log(`rotation timer error: ${e.message}`);
6189
6269
  } finally {
6190
- writeRunningMarker(stateRoot, { pid: process.pid, bootTs, lastHeartbeatTs: (/* @__PURE__ */ new Date()).toISOString() }, log);
6270
+ writeRunningMarker(stateRoot2, { pid: process.pid, bootTs, lastHeartbeatTs: (/* @__PURE__ */ new Date()).toISOString() }, log);
6191
6271
  }
6192
6272
  };
6193
6273
  rotationTimer = setInterval(() => {
@@ -6201,8 +6281,8 @@ function startDaemon(ctx, opts, pkgVersion) {
6201
6281
  const uptimeMs = Math.round(process.uptime() * 1e3);
6202
6282
  const inFlight = inFlightDelivery();
6203
6283
  log(`exit pid=${process.pid} reason=${reason} ppid=${ppid} launchd=${ppid === 1} uptimeMs=${uptimeMs} inFlightDelivery=${inFlight ? `${inFlight.project}#${inFlight.seq}(defers=${inFlight.deferCount})` : "none"}`);
6204
- writeExitMarker(stateRoot, { ts: (/* @__PURE__ */ new Date()).toISOString(), pid: process.pid, reason, ppid, uptimeMs, inFlightDelivery: inFlight }, log);
6205
- removeRunningMarker(stateRoot, log);
6284
+ writeExitMarker(stateRoot2, { ts: (/* @__PURE__ */ new Date()).toISOString(), pid: process.pid, reason, ppid, uptimeMs, inFlightDelivery: inFlight }, log);
6285
+ removeRunningMarker(stateRoot2, log);
6206
6286
  if (deliveryTimer)
6207
6287
  clearInterval(deliveryTimer);
6208
6288
  if (probeTimer)
@@ -6229,9 +6309,9 @@ function startDaemon(ctx, opts, pkgVersion) {
6229
6309
  await ctx.routerService?.stop();
6230
6310
  } catch {
6231
6311
  }
6232
- return new Promise((resolve4) => server.close(() => {
6312
+ return new Promise((resolve5) => server.close(() => {
6233
6313
  log(`exit-complete pid=${process.pid}`);
6234
- resolve4();
6314
+ resolve5();
6235
6315
  }));
6236
6316
  },
6237
6317
  tickDelivery: deliveryTick,
@@ -6260,11 +6340,12 @@ var init_start = __esm({
6260
6340
 
6261
6341
  // packages/core/dist/session-freshness.js
6262
6342
  import crypto from "crypto";
6263
- import fs11 from "fs";
6264
- import path12 from "path";
6265
- function loadSessions(sessionsPath) {
6343
+ import fs12 from "fs";
6344
+ import path13 from "path";
6345
+ function loadSessions(sessionsPath, legacyPath) {
6266
6346
  try {
6267
- return JSON.parse(readConfigFileSync(sessionsPath));
6347
+ const readPath = legacyPath ? resolveReadPath(sessionsPath, legacyPath) : sessionsPath;
6348
+ return JSON.parse(readConfigFileSync(readPath));
6268
6349
  } catch {
6269
6350
  return { workspaces: {} };
6270
6351
  }
@@ -6274,26 +6355,26 @@ function saveSessions(sessionsPath, sessions) {
6274
6355
  }
6275
6356
  function computeTemplateHash(role, templatesDir) {
6276
6357
  const hash = crypto.createHash("sha256");
6277
- const roleFile = path12.join(templatesDir, `${role}.claude.md`);
6278
- const legacyRoleFile = path12.join(templatesDir, `${role}.CLAUDE.md`);
6279
- if (fs11.existsSync(roleFile)) {
6280
- hash.update(fs11.readFileSync(roleFile, "utf-8"));
6281
- } else if (fs11.existsSync(legacyRoleFile)) {
6282
- hash.update(fs11.readFileSync(legacyRoleFile, "utf-8"));
6358
+ const roleFile = path13.join(templatesDir, `${role}.claude.md`);
6359
+ const legacyRoleFile = path13.join(templatesDir, `${role}.CLAUDE.md`);
6360
+ if (fs12.existsSync(roleFile)) {
6361
+ hash.update(fs12.readFileSync(roleFile, "utf-8"));
6362
+ } else if (fs12.existsSync(legacyRoleFile)) {
6363
+ hash.update(fs12.readFileSync(legacyRoleFile, "utf-8"));
6283
6364
  }
6284
- const pluginSkillsDir = path12.join(templatesDir, "..", "plugin", "skills");
6285
- if (fs11.existsSync(pluginSkillsDir)) {
6286
- for (const skill of fs11.readdirSync(pluginSkillsDir).sort()) {
6287
- const skillFile = path12.join(pluginSkillsDir, skill, "SKILL.md");
6288
- if (fs11.existsSync(skillFile)) {
6289
- hash.update(fs11.readFileSync(skillFile, "utf-8"));
6365
+ const pluginSkillsDir = path13.join(templatesDir, "..", "plugin", "skills");
6366
+ if (fs12.existsSync(pluginSkillsDir)) {
6367
+ for (const skill of fs12.readdirSync(pluginSkillsDir).sort()) {
6368
+ const skillFile = path13.join(pluginSkillsDir, skill, "SKILL.md");
6369
+ if (fs12.existsSync(skillFile)) {
6370
+ hash.update(fs12.readFileSync(skillFile, "utf-8"));
6290
6371
  }
6291
6372
  }
6292
6373
  }
6293
6374
  return hash.digest("hex").slice(0, 16);
6294
6375
  }
6295
6376
  function shouldStartFresh(workspaceName, role, opts) {
6296
- const sessions = loadSessions(opts.sessionsPath);
6377
+ const sessions = loadSessions(opts.sessionsPath, opts.legacySessionsPath);
6297
6378
  const record = sessions.workspaces[workspaceName];
6298
6379
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6299
6380
  const currentHash = computeTemplateHash(role, opts.templatesDir);
@@ -6309,7 +6390,7 @@ function shouldStartFresh(workspaceName, role, opts) {
6309
6390
  return { fresh: false };
6310
6391
  }
6311
6392
  function recordSession(workspaceName, role, opts) {
6312
- const sessions = loadSessions(opts.sessionsPath);
6393
+ const sessions = loadSessions(opts.sessionsPath, opts.legacySessionsPath);
6313
6394
  sessions.workspaces[workspaceName] = {
6314
6395
  lastLaunched: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
6315
6396
  templateHash: computeTemplateHash(role, opts.templatesDir)
@@ -6523,7 +6604,7 @@ function createIsCaptainAlive(sock) {
6523
6604
  };
6524
6605
  }
6525
6606
  function createLaunch(cliBin, log) {
6526
- return (project) => new Promise((resolve4, reject) => {
6607
+ return (project) => new Promise((resolve5, reject) => {
6527
6608
  execFile(process.execPath, [cliBin, "launch", project, "--headless"], { timeout: 3e4 }, (err, stdout, stderr) => {
6528
6609
  const output = capOutput(stdout ?? "", stderr ?? "");
6529
6610
  if (err) {
@@ -6533,7 +6614,7 @@ function createLaunch(cliBin, log) {
6533
6614
  }
6534
6615
  if (output !== "(no output)")
6535
6616
  log?.(`launch ${project}: ${output}`);
6536
- resolve4();
6617
+ resolve5();
6537
6618
  });
6538
6619
  });
6539
6620
  }
@@ -6670,16 +6751,16 @@ var init_format = __esm({
6670
6751
  });
6671
6752
 
6672
6753
  // packages/core/dist/telegram/state.js
6673
- import path13 from "path";
6674
- function statePath(stateRoot) {
6675
- return path13.join(stateRoot, "telegram-state.json");
6754
+ import path14 from "path";
6755
+ function statePath(stateRoot2) {
6756
+ return path14.join(stateRoot2, "telegram-state.json");
6676
6757
  }
6677
6758
  function topicKey(project, scope = "project") {
6678
6759
  return `${project}::${scope}`;
6679
6760
  }
6680
- function loadState(stateRoot) {
6761
+ function loadState(stateRoot2) {
6681
6762
  try {
6682
- const raw = readConfigFileSync(statePath(stateRoot));
6763
+ const raw = readConfigFileSync(statePath(stateRoot2));
6683
6764
  const data = JSON.parse(raw);
6684
6765
  const result = {
6685
6766
  offset: typeof data.offset === "number" ? data.offset : 0,
@@ -6695,16 +6776,16 @@ function loadState(stateRoot) {
6695
6776
  return { offset: 0, topics: {}, notify: {} };
6696
6777
  }
6697
6778
  }
6698
- function saveState(stateRoot, s) {
6699
- writeConfigFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
6779
+ function saveState(stateRoot2, s) {
6780
+ writeConfigFileSync(statePath(stateRoot2), JSON.stringify(s, null, 2) + "\n");
6700
6781
  }
6701
- function setTopic(stateRoot, project, topicId, scope = "project") {
6702
- const s = loadState(stateRoot);
6782
+ function setTopic(stateRoot2, project, topicId, scope = "project") {
6783
+ const s = loadState(stateRoot2);
6703
6784
  s.topics[topicKey(project, scope)] = topicId;
6704
- saveState(stateRoot, s);
6785
+ saveState(stateRoot2, s);
6705
6786
  }
6706
- function pruneTopics(stateRoot, keep) {
6707
- const s = loadState(stateRoot);
6787
+ function pruneTopics(stateRoot2, keep) {
6788
+ const s = loadState(stateRoot2);
6708
6789
  const removed = Object.keys(s.topics).filter((key) => {
6709
6790
  const sep3 = key.indexOf("::");
6710
6791
  return !keep(sep3 === -1 ? key : key.slice(0, sep3));
@@ -6713,60 +6794,60 @@ function pruneTopics(stateRoot, keep) {
6713
6794
  return [];
6714
6795
  for (const key of removed)
6715
6796
  delete s.topics[key];
6716
- saveState(stateRoot, s);
6797
+ saveState(stateRoot2, s);
6717
6798
  return removed;
6718
6799
  }
6719
- function isNotifyActive(stateRoot, project) {
6720
- return loadState(stateRoot).notify[project] === true;
6800
+ function isNotifyActive(stateRoot2, project) {
6801
+ return loadState(stateRoot2).notify[project] === true;
6721
6802
  }
6722
- function setLastUserId(stateRoot, id) {
6723
- const s = loadState(stateRoot);
6803
+ function setLastUserId(stateRoot2, id) {
6804
+ const s = loadState(stateRoot2);
6724
6805
  s.lastUserId = id;
6725
- saveState(stateRoot, s);
6806
+ saveState(stateRoot2, s);
6726
6807
  }
6727
- function setNotify(stateRoot, project, active) {
6728
- const s = loadState(stateRoot);
6808
+ function setNotify(stateRoot2, project, active) {
6809
+ const s = loadState(stateRoot2);
6729
6810
  s.notify[project] = active;
6730
- saveState(stateRoot, s);
6811
+ saveState(stateRoot2, s);
6731
6812
  }
6732
- function loadPending(stateRoot) {
6733
- return loadState(stateRoot).pending ?? {};
6813
+ function loadPending(stateRoot2) {
6814
+ return loadState(stateRoot2).pending ?? {};
6734
6815
  }
6735
- function setPending(stateRoot, project, p) {
6736
- const s = loadState(stateRoot);
6816
+ function setPending(stateRoot2, project, p) {
6817
+ const s = loadState(stateRoot2);
6737
6818
  s.pending = { ...s.pending ?? {}, [project]: p };
6738
- saveState(stateRoot, s);
6819
+ saveState(stateRoot2, s);
6739
6820
  }
6740
- function clearPending(stateRoot, project) {
6741
- const s = loadState(stateRoot);
6821
+ function clearPending(stateRoot2, project) {
6822
+ const s = loadState(stateRoot2);
6742
6823
  if (!s.pending || !(project in s.pending))
6743
6824
  return;
6744
6825
  delete s.pending[project];
6745
6826
  if (Object.keys(s.pending).length === 0)
6746
6827
  delete s.pending;
6747
- saveState(stateRoot, s);
6828
+ saveState(stateRoot2, s);
6748
6829
  }
6749
- function markPendingWarned(stateRoot, project, at) {
6750
- const s = loadState(stateRoot);
6830
+ function markPendingWarned(stateRoot2, project, at) {
6831
+ const s = loadState(stateRoot2);
6751
6832
  const p = s.pending?.[project];
6752
6833
  if (!p)
6753
6834
  return;
6754
6835
  s.pending[project] = { ...p, warnedAt: at };
6755
- saveState(stateRoot, s);
6836
+ saveState(stateRoot2, s);
6756
6837
  }
6757
- function notePaneScreen(stateRoot, project, hash, at) {
6758
- const s = loadState(stateRoot);
6838
+ function notePaneScreen(stateRoot2, project, hash, at) {
6839
+ const s = loadState(stateRoot2);
6759
6840
  const p = s.pending?.[project];
6760
6841
  if (!p)
6761
6842
  return void 0;
6762
6843
  if (p.paneHash === hash && p.paneChangedAt !== void 0)
6763
6844
  return at - p.paneChangedAt;
6764
6845
  s.pending[project] = { ...p, paneHash: hash, paneChangedAt: at };
6765
- saveState(stateRoot, s);
6846
+ saveState(stateRoot2, s);
6766
6847
  return void 0;
6767
6848
  }
6768
- function findProjectByThread(stateRoot, threadId) {
6769
- const s = loadState(stateRoot);
6849
+ function findProjectByThread(stateRoot2, threadId) {
6850
+ const s = loadState(stateRoot2);
6770
6851
  for (const [key, id] of Object.entries(s.topics)) {
6771
6852
  if (id !== threadId)
6772
6853
  continue;
@@ -6888,7 +6969,7 @@ function formatWatchdogWarning(project, read, minutes) {
6888
6969
  }
6889
6970
  }
6890
6971
  function createInboundLifecycle(opts) {
6891
- const { stateRoot, cfg, sendChatAction, sendReply, readPane, log } = opts;
6972
+ const { stateRoot: stateRoot2, cfg, sendChatAction, sendReply, readPane, log } = opts;
6892
6973
  const now = opts.now ?? Date.now;
6893
6974
  const schedule = opts.schedule ?? defaultSchedule;
6894
6975
  const typingMs = opts.typingMs ?? TYPING_KEEPALIVE_MS;
@@ -6904,7 +6985,7 @@ function createInboundLifecycle(opts) {
6904
6985
  const tick = () => {
6905
6986
  if (!running || !active.has(project))
6906
6987
  return;
6907
- const p = loadPending(stateRoot)[project];
6988
+ const p = loadPending(stateRoot2)[project];
6908
6989
  if (!p) {
6909
6990
  active.delete(project);
6910
6991
  return;
@@ -6918,7 +6999,7 @@ function createInboundLifecycle(opts) {
6918
6999
  schedule(tick, typingMs);
6919
7000
  }
6920
7001
  async function warn(project, threadId) {
6921
- markPendingWarned(stateRoot, project, now());
7002
+ markPendingWarned(stateRoot2, project, now());
6922
7003
  let read = { status: "unreadable" };
6923
7004
  try {
6924
7005
  if (readPane)
@@ -6935,7 +7016,7 @@ function createInboundLifecycle(opts) {
6935
7016
  return {
6936
7017
  start() {
6937
7018
  running = true;
6938
- for (const [project, p] of Object.entries(loadPending(stateRoot))) {
7019
+ for (const [project, p] of Object.entries(loadPending(stateRoot2))) {
6939
7020
  void (async () => {
6940
7021
  let read = { status: "unreadable" };
6941
7022
  try {
@@ -6944,11 +7025,11 @@ function createInboundLifecycle(opts) {
6944
7025
  } catch (e) {
6945
7026
  log(`telegram resume pane read failed project=${project}: ${e.message}`);
6946
7027
  }
6947
- const still = loadPending(stateRoot)[project];
7028
+ const still = loadPending(stateRoot2)[project];
6948
7029
  if (!still || still.startedAt !== p.startedAt)
6949
7030
  return;
6950
7031
  if (read.status === "no-session") {
6951
- clearPending(stateRoot, project);
7032
+ clearPending(stateRoot2, project);
6952
7033
  log(`telegram typing lifecycle cleared for ${project}: captain session gone on boot`);
6953
7034
  return;
6954
7035
  }
@@ -6963,13 +7044,13 @@ function createInboundLifecycle(opts) {
6963
7044
  active.clear();
6964
7045
  },
6965
7046
  begin(project, threadId) {
6966
- setPending(stateRoot, project, { threadId, startedAt: now() });
7047
+ setPending(stateRoot2, project, { threadId, startedAt: now() });
6967
7048
  issue(project, threadId);
6968
7049
  if (running && !active.has(project))
6969
7050
  drain(project);
6970
7051
  },
6971
7052
  pending() {
6972
- return loadPending(stateRoot);
7053
+ return loadPending(stateRoot2);
6973
7054
  }
6974
7055
  };
6975
7056
  }
@@ -7164,9 +7245,9 @@ var init_tiers = __esm({
7164
7245
  });
7165
7246
 
7166
7247
  // packages/core/dist/telegram/bridge.js
7167
- import fs12 from "fs";
7168
- import os6 from "os";
7169
- import path14 from "path";
7248
+ import fs13 from "fs";
7249
+ import os7 from "os";
7250
+ import path15 from "path";
7170
7251
  import crypto2 from "crypto";
7171
7252
  function formatInboundReceipt(project, outcome) {
7172
7253
  if (!outcome)
@@ -7185,7 +7266,7 @@ function formatInboundReceipt(project, outcome) {
7185
7266
  }
7186
7267
  function telegramPollLockPath(token) {
7187
7268
  const hash = crypto2.createHash("sha256").update(token).digest("hex").slice(0, 16);
7188
- return path14.join(os6.tmpdir(), `squadrant-telegram-poll-${hash}.lock`);
7269
+ return path15.join(os7.tmpdir(), `squadrant-telegram-poll-${hash}.lock`);
7189
7270
  }
7190
7271
  function pidAlive(pid) {
7191
7272
  try {
@@ -7199,9 +7280,9 @@ function lockIsHeld(file) {
7199
7280
  let pid;
7200
7281
  let ageMs;
7201
7282
  try {
7202
- const parsed = Number.parseInt(fs12.readFileSync(file, "utf8").trim(), 10);
7283
+ const parsed = Number.parseInt(fs13.readFileSync(file, "utf8").trim(), 10);
7203
7284
  pid = Number.isFinite(parsed) ? parsed : void 0;
7204
- ageMs = Date.now() - fs12.statSync(file).mtimeMs;
7285
+ ageMs = Date.now() - fs13.statSync(file).mtimeMs;
7205
7286
  } catch {
7206
7287
  return false;
7207
7288
  }
@@ -7213,12 +7294,12 @@ function acquirePollLock(token) {
7213
7294
  const file = telegramPollLockPath(token);
7214
7295
  for (let attempt = 0; attempt < 2; attempt++) {
7215
7296
  try {
7216
- const fd = fs12.openSync(file, "wx");
7217
- fs12.writeSync(fd, String(process.pid));
7218
- fs12.closeSync(fd);
7297
+ const fd = fs13.openSync(file, "wx");
7298
+ fs13.writeSync(fd, String(process.pid));
7299
+ fs13.closeSync(fd);
7219
7300
  return () => {
7220
7301
  try {
7221
- fs12.unlinkSync(file);
7302
+ fs13.unlinkSync(file);
7222
7303
  } catch {
7223
7304
  }
7224
7305
  };
@@ -7227,7 +7308,7 @@ function acquirePollLock(token) {
7227
7308
  return null;
7228
7309
  if (attempt === 0 && !lockIsHeld(file)) {
7229
7310
  try {
7230
- fs12.unlinkSync(file);
7311
+ fs13.unlinkSync(file);
7231
7312
  } catch {
7232
7313
  }
7233
7314
  continue;
@@ -7246,7 +7327,7 @@ function foreignPollLockHolder(token, selfPid = process.pid) {
7246
7327
  const file = telegramPollLockPath(token);
7247
7328
  let pid;
7248
7329
  try {
7249
- const parsed = Number.parseInt(fs12.readFileSync(file, "utf8").trim(), 10);
7330
+ const parsed = Number.parseInt(fs13.readFileSync(file, "utf8").trim(), 10);
7250
7331
  if (!Number.isFinite(parsed))
7251
7332
  return null;
7252
7333
  pid = parsed;
@@ -7287,9 +7368,9 @@ function notifyToggle(text) {
7287
7368
  return null;
7288
7369
  }
7289
7370
  function createTelegramBridge(opts) {
7290
- const { cfg, stateRoot, client, appendCaptainMessage: appendCaptainMessage2, log, ensureCaptainAlive, runCommand, sendReply } = opts;
7371
+ const { cfg, stateRoot: stateRoot2, client, appendCaptainMessage: appendCaptainMessage2, log, ensureCaptainAlive, runCommand, sendReply } = opts;
7291
7372
  const lifecycle = opts.lifecycle;
7292
- const configRoot = opts.configRoot ?? path14.join(os6.homedir(), ".config", "squadrant");
7373
+ const configRoot = opts.configRoot ?? path15.join(os7.homedir(), ".config", "squadrant");
7293
7374
  const pollMs = cfg.pollMs ?? 1e3;
7294
7375
  const schedule = opts.schedule ?? defaultSchedule2;
7295
7376
  const lockToken = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
@@ -7303,17 +7384,17 @@ function createTelegramBridge(opts) {
7303
7384
  let lastError = null;
7304
7385
  let lastErrorAt = null;
7305
7386
  function persistOffset(next) {
7306
- const s = loadState(stateRoot);
7387
+ const s = loadState(stateRoot2);
7307
7388
  s.offset = next;
7308
- saveState(stateRoot, s);
7389
+ saveState(stateRoot2, s);
7309
7390
  }
7310
7391
  async function sendToTopic(project, text) {
7311
- const { topicId } = await runTelegramLink({ project, cfg, client, stateRoot });
7392
+ const { topicId } = await runTelegramLink({ project, cfg, client, stateRoot: stateRoot2 });
7312
7393
  await client.sendMessage(cfg.supergroupId, topicId, text);
7313
7394
  }
7314
7395
  async function deliverOutbound(project, ev2) {
7315
7396
  const resolved = resolveNotify(cfg.notify, loadProjectOverride(project, configRoot));
7316
- const live = loadState(stateRoot).notify[project];
7397
+ const live = loadState(stateRoot2).notify[project];
7317
7398
  const active = live ?? resolved.active;
7318
7399
  if (!active)
7319
7400
  return;
@@ -7333,7 +7414,7 @@ ${formatUsageLine(usage2)}`;
7333
7414
  }
7334
7415
  function resolveLiveNotify(project) {
7335
7416
  const resolved = resolveNotify(cfg.notify, loadProjectOverride(project, configRoot));
7336
- const live = loadState(stateRoot).notify[project];
7417
+ const live = loadState(stateRoot2).notify[project];
7337
7418
  return { ...resolved, active: live ?? resolved.active };
7338
7419
  }
7339
7420
  async function editMarkup(chatId, messageId, markup) {
@@ -7363,14 +7444,14 @@ ${formatUsageLine(usage2)}`;
7363
7444
  const chatId = cq.message.chat.id;
7364
7445
  const messageId = cq.message.message_id;
7365
7446
  if (action.t === "notify") {
7366
- const resolved = findProjectByThread(stateRoot, cq.message.message_thread_id ?? -1);
7447
+ const resolved = findProjectByThread(stateRoot2, cq.message.message_thread_id ?? -1);
7367
7448
  if (!resolved) {
7368
7449
  await client.answerCallbackQuery(cq.id, "no project for this topic");
7369
7450
  return;
7370
7451
  }
7371
7452
  const project2 = resolved.project;
7372
7453
  if (action.dim === "active") {
7373
- setNotify(stateRoot, project2, action.val === "on");
7454
+ setNotify(stateRoot2, project2, action.val === "on");
7374
7455
  } else if (action.dim === "cap") {
7375
7456
  saveProjectOverride(project2, { telegram: { notify: { cap: action.val === "on" } } }, configRoot);
7376
7457
  } else {
@@ -7402,10 +7483,10 @@ ${formatUsageLine(usage2)}`;
7402
7483
  await runCommand(["launch", project]);
7403
7484
  await client.answerCallbackQuery(cq.id, `launching ${project}`);
7404
7485
  } else if (act === "mu") {
7405
- setNotify(stateRoot, project, false);
7486
+ setNotify(stateRoot2, project, false);
7406
7487
  await client.answerCallbackQuery(cq.id, `\u{1F515} muted ${project}`);
7407
7488
  } else {
7408
- setNotify(stateRoot, project, true);
7489
+ setNotify(stateRoot2, project, true);
7409
7490
  await client.answerCallbackQuery(cq.id, `\u{1F514} unmuted ${project}`);
7410
7491
  }
7411
7492
  } catch (e) {
@@ -7430,14 +7511,14 @@ ${formatUsageLine(usage2)}`;
7430
7511
  }
7431
7512
  function currentEffort() {
7432
7513
  try {
7433
- return loadConfig(path14.join(configRoot, "config.json")).defaults.effort ?? "balance";
7514
+ return loadConfig(path15.join(configRoot, "config.json")).defaults.effort ?? "balance";
7434
7515
  } catch {
7435
7516
  return "balance";
7436
7517
  }
7437
7518
  }
7438
7519
  function projectNames() {
7439
7520
  try {
7440
- return Object.keys(loadConfig(path14.join(configRoot, "config.json")).projects);
7521
+ return Object.keys(loadConfig(path15.join(configRoot, "config.json")).projects);
7441
7522
  } catch {
7442
7523
  return [];
7443
7524
  }
@@ -7497,7 +7578,7 @@ ${formatUsageLine(usage2)}`;
7497
7578
  await runChannelCommand(text, fromId, void 0);
7498
7579
  }
7499
7580
  async function handleProjectTopic(text, threadId, fromId, messageId, media) {
7500
- const resolved = findProjectByThread(stateRoot, threadId);
7581
+ const resolved = findProjectByThread(stateRoot2, threadId);
7501
7582
  if (!resolved) {
7502
7583
  log(`telegram inbound in unbound topic thread=${threadId} \u2014 no project linked, message dropped`);
7503
7584
  await reply(threadId, "\u26A0\uFE0F this topic isn't linked to a project \u2014 run: squadrant telegram link <project>");
@@ -7517,7 +7598,7 @@ ${formatUsageLine(usage2)}`;
7517
7598
  await reply(threadId, "\u26D4 not authorized");
7518
7599
  return;
7519
7600
  }
7520
- setNotify(stateRoot, resolved.project, toggle);
7601
+ setNotify(stateRoot2, resolved.project, toggle);
7521
7602
  await reply(threadId, toggle ? `\u{1F514} ${resolved.project} notifications ON` : `\u{1F515} ${resolved.project} notifications OFF`);
7522
7603
  return;
7523
7604
  }
@@ -7555,7 +7636,7 @@ ${formatUsageLine(usage2)}`;
7555
7636
  if (messageId !== void 0) {
7556
7637
  void Promise.resolve(client.setMessageReaction?.(cfg.supergroupId, messageId, "\u{1F44D}")).catch((e) => log(`telegram stage-1 reaction failed project=${resolved.project}: ${e.message}`));
7557
7638
  }
7558
- setNotify(stateRoot, resolved.project, true);
7639
+ setNotify(stateRoot2, resolved.project, true);
7559
7640
  if (ensureCaptainAlive && isControlEnabled(cfg) && isAuthorized(fromId, cfg)) {
7560
7641
  void ensureCaptainAlive(resolved.project).then((r) => {
7561
7642
  if (r === "timeout") {
@@ -7572,7 +7653,7 @@ ${formatUsageLine(usage2)}`;
7572
7653
  }
7573
7654
  const deliveryHeld = outcome?.status === "held";
7574
7655
  if (!handled) {
7575
- await appendCaptainMessage2({ stateRoot, project: resolved.project, text: formatInbound(text), source: "telegram" });
7656
+ await appendCaptainMessage2({ stateRoot: stateRoot2, project: resolved.project, text: formatInbound(text), source: "telegram" });
7576
7657
  outcome = void 0;
7577
7658
  }
7578
7659
  const receipt = formatInboundReceipt(resolved.project, outcome);
@@ -7601,8 +7682,8 @@ ${formatUsageLine(usage2)}`;
7601
7682
  return;
7602
7683
  if (!cfg.chats.includes(m.chat.id))
7603
7684
  return;
7604
- if (m.from?.id !== void 0 && loadState(stateRoot).lastUserId !== m.from.id) {
7605
- setLastUserId(stateRoot, m.from.id);
7685
+ if (m.from?.id !== void 0 && loadState(stateRoot2).lastUserId !== m.from.id) {
7686
+ setLastUserId(stateRoot2, m.from.id);
7606
7687
  }
7607
7688
  const spawnProject = parseSpawnPrompt(m.reply_to_message?.text);
7608
7689
  if (spawnProject) {
@@ -7661,7 +7742,7 @@ ${formatUsageLine(usage2)}`;
7661
7742
  pollAbort = ac;
7662
7743
  let waitMs = pollMs;
7663
7744
  try {
7664
- const offset = loadState(stateRoot).offset;
7745
+ const offset = loadState(stateRoot2).offset;
7665
7746
  const updates = await client.getUpdates(offset, LONG_POLL_SEC, ac.signal);
7666
7747
  conflictCount = 0;
7667
7748
  for (const u of updates) {
@@ -7709,7 +7790,7 @@ ${formatUsageLine(usage2)}`;
7709
7790
  const known = opts.registeredProjects?.();
7710
7791
  if (known !== void 0) {
7711
7792
  try {
7712
- const removed = pruneTopics(stateRoot, (p) => known.includes(p));
7793
+ const removed = pruneTopics(stateRoot2, (p) => known.includes(p));
7713
7794
  if (removed.length > 0)
7714
7795
  log(`telegram registry pruned ${removed.length} stale topic link(s): ${removed.join(", ")}`);
7715
7796
  } catch (e) {
@@ -7779,9 +7860,9 @@ var init_bridge = __esm({
7779
7860
 
7780
7861
  // packages/core/dist/restart-daemon.js
7781
7862
  import { execFileSync as execFileSync5 } from "child_process";
7782
- import { existsSync as existsSync10 } from "fs";
7863
+ import { existsSync as existsSync11 } from "fs";
7783
7864
  function defaultIsRunning() {
7784
- return existsSync10(DAEMON_SOCK_PATH);
7865
+ return existsSync11(DAEMON_SOCK_PATH);
7785
7866
  }
7786
7867
  function defaultRunKickstart() {
7787
7868
  const uid = process.getuid?.() ?? 0;
@@ -7815,7 +7896,7 @@ var init_restart_daemon = __esm({
7815
7896
  });
7816
7897
 
7817
7898
  // packages/core/dist/telegram/setup.js
7818
- import fs13 from "fs";
7899
+ import fs14 from "fs";
7819
7900
  function resolveSetupGroup(existingSupergroupId, opts) {
7820
7901
  if (existingSupergroupId !== void 0 && !opts.redetect)
7821
7902
  return "reuse";
@@ -7847,8 +7928,8 @@ function resolveSetupToken(existingToken, opts) {
7847
7928
  return "prompt";
7848
7929
  return "try-reuse";
7849
7930
  }
7850
- function resolveSetupUserId(flagUserId, detectedUserId, stateRoot) {
7851
- return flagUserId ?? detectedUserId ?? loadState(stateRoot).lastUserId;
7931
+ function resolveSetupUserId(flagUserId, detectedUserId, stateRoot2) {
7932
+ return flagUserId ?? detectedUserId ?? loadState(stateRoot2).lastUserId;
7852
7933
  }
7853
7934
  async function runRegisterCommands(opts) {
7854
7935
  await opts.client.setMyCommands(BOT_COMMANDS);
@@ -7866,7 +7947,7 @@ function writeTelegramConfig(configPath, opts) {
7866
7947
  let config;
7867
7948
  let raw = null;
7868
7949
  try {
7869
- raw = fs13.readFileSync(configPath, "utf-8");
7950
+ raw = fs14.readFileSync(configPath, "utf-8");
7870
7951
  } catch (err) {
7871
7952
  if (err.code !== "ENOENT") {
7872
7953
  throw new Error(`refusing to overwrite unreadable config at ${configPath}: ${String(err)}`);
@@ -8098,8 +8179,8 @@ var init_stream = __esm({
8098
8179
  // packages/core/dist/router/shim.js
8099
8180
  import { createServer as createServer3 } from "http";
8100
8181
  import { Readable } from "stream";
8101
- function joinUrl(base, path43) {
8102
- return base.replace(/\/+$/, "") + path43;
8182
+ function joinUrl(base, path44) {
8183
+ return base.replace(/\/+$/, "") + path44;
8103
8184
  }
8104
8185
  async function readBody(req) {
8105
8186
  const chunks = [];
@@ -8275,8 +8356,8 @@ function createRouterShim(opts) {
8275
8356
  writeJson(res, 200, { input_tokens: Math.max(1, Math.ceil(text.length / 4)) });
8276
8357
  }
8277
8358
  function handler(req, res) {
8278
- const path43 = pathnameOf(req.url);
8279
- if (req.method === "POST" && path43 === "/v1/messages") {
8359
+ const path44 = pathnameOf(req.url);
8360
+ if (req.method === "POST" && path44 === "/v1/messages") {
8280
8361
  void handleMessages(req, res).catch((err) => {
8281
8362
  log(`router internal error: ${err instanceof Error ? err.message : String(err)}`);
8282
8363
  if (!res.headersSent) {
@@ -8288,18 +8369,18 @@ function createRouterShim(opts) {
8288
8369
  });
8289
8370
  return;
8290
8371
  }
8291
- if (req.method === "POST" && path43 === "/v1/messages/count_tokens") {
8372
+ if (req.method === "POST" && path44 === "/v1/messages/count_tokens") {
8292
8373
  void handleCountTokens(req, res).catch(() => {
8293
8374
  if (!res.headersSent)
8294
8375
  writeJson(res, 502, anthropicError(502, "api_error", "router internal error").body);
8295
8376
  });
8296
8377
  return;
8297
8378
  }
8298
- if (req.method === "GET" && path43 === "/v1/models") {
8379
+ if (req.method === "GET" && path44 === "/v1/models") {
8299
8380
  writeJson(res, 200, modelsList([...advertisedModels]));
8300
8381
  return;
8301
8382
  }
8302
- if (req.method === "GET" && path43 === "/healthz") {
8383
+ if (req.method === "GET" && path44 === "/healthz") {
8303
8384
  writeJson(res, 200, { ready: server?.listening === true, upstreamReachable, lastError });
8304
8385
  return;
8305
8386
  }
@@ -8311,7 +8392,7 @@ function createRouterShim(opts) {
8311
8392
  return;
8312
8393
  if (starting)
8313
8394
  return starting;
8314
- starting = new Promise((resolve4, reject) => {
8395
+ starting = new Promise((resolve5, reject) => {
8315
8396
  const s = createServer3(handler);
8316
8397
  const onStartupError = (err) => {
8317
8398
  s.off("error", onStartupError);
@@ -8327,7 +8408,7 @@ function createRouterShim(opts) {
8327
8408
  server = s;
8328
8409
  const addr = s.address();
8329
8410
  boundPort = typeof addr === "object" && addr ? addr.port : 0;
8330
- resolve4();
8411
+ resolve5();
8331
8412
  });
8332
8413
  });
8333
8414
  try {
@@ -8347,7 +8428,7 @@ function createRouterShim(opts) {
8347
8428
  server = void 0;
8348
8429
  boundPort = 0;
8349
8430
  s.closeAllConnections?.();
8350
- await new Promise((resolve4) => s.close(() => resolve4()));
8431
+ await new Promise((resolve5) => s.close(() => resolve5()));
8351
8432
  },
8352
8433
  url() {
8353
8434
  return `http://${opts.host ?? "127.0.0.1"}:${boundPort}`;
@@ -8541,7 +8622,6 @@ var init_captain_router = __esm({
8541
8622
  // packages/core/dist/group-dispatch.js
8542
8623
  import { randomUUID as randomUUID4 } from "crypto";
8543
8624
  import { createConnection as createConnection2 } from "net";
8544
- import { join as join16 } from "path";
8545
8625
  function resolveCurrentProject(config) {
8546
8626
  const cwd = process.cwd();
8547
8627
  for (const [name, proj] of Object.entries(config.projects)) {
@@ -8552,8 +8632,8 @@ function resolveCurrentProject(config) {
8552
8632
  return null;
8553
8633
  }
8554
8634
  async function probeCaptainChannel(project, opts = {}) {
8555
- const stateRoot = opts.stateRoot ?? join16(CONFIG_DIR, "state");
8556
- const addr = readCaptainAddress(stateRoot, project);
8635
+ const stateRoot2 = opts.stateRoot ?? stateRoot();
8636
+ const addr = readCaptainAddress(stateRoot2, project);
8557
8637
  if (!addr)
8558
8638
  return false;
8559
8639
  if (addr.agent === "opencode") {
@@ -8568,11 +8648,11 @@ async function probeCaptainChannel(project, opts = {}) {
8568
8648
  }
8569
8649
  }
8570
8650
  async function httpReachable(port, fetchImpl, timeoutMs) {
8571
- for (const path43 of ["/session", "/api/session"]) {
8651
+ for (const path44 of ["/session", "/api/session"]) {
8572
8652
  const ac = new AbortController();
8573
8653
  const t = setTimeout(() => ac.abort(), timeoutMs);
8574
8654
  try {
8575
- const res = await fetchImpl(`http://127.0.0.1:${port}${path43}`, { signal: ac.signal });
8655
+ const res = await fetchImpl(`http://127.0.0.1:${port}${path44}`, { signal: ac.signal });
8576
8656
  if (res.ok)
8577
8657
  return true;
8578
8658
  } catch {
@@ -8583,7 +8663,7 @@ async function httpReachable(port, fetchImpl, timeoutMs) {
8583
8663
  return false;
8584
8664
  }
8585
8665
  function socketAccepts(socketPath, timeoutMs = 2e3) {
8586
- return new Promise((resolve4) => {
8666
+ return new Promise((resolve5) => {
8587
8667
  let settled = false;
8588
8668
  const sock = createConnection2(socketPath);
8589
8669
  const done = (v2) => {
@@ -8591,7 +8671,7 @@ function socketAccepts(socketPath, timeoutMs = 2e3) {
8591
8671
  return;
8592
8672
  settled = true;
8593
8673
  sock.destroy();
8594
- resolve4(v2);
8674
+ resolve5(v2);
8595
8675
  };
8596
8676
  sock.setTimeout(timeoutMs, () => done(false));
8597
8677
  sock.once("connect", () => done(true));
@@ -8751,6 +8831,7 @@ async function launchOneWorkspace(opts) {
8751
8831
  if (!forceFresh) {
8752
8832
  const auto = shouldStartFresh(opts.workspaceName, opts.role, {
8753
8833
  sessionsPath: opts.sessionsPath,
8834
+ legacySessionsPath: opts.legacySessionsPath,
8754
8835
  templatesDir: opts.templatesDir
8755
8836
  });
8756
8837
  if (auto.fresh && opts.keepOverride && auto.reason !== "first launch") {
@@ -8764,6 +8845,7 @@ async function launchOneWorkspace(opts) {
8764
8845
  const agentCmd = opts.role === "captain" ? `SQUADRANT_ROLE=captain ${builtCmd}` : builtCmd;
8765
8846
  recordSession(opts.workspaceName, opts.role, {
8766
8847
  sessionsPath: opts.sessionsPath,
8848
+ legacySessionsPath: opts.legacySessionsPath,
8767
8849
  templatesDir: opts.templatesDir
8768
8850
  });
8769
8851
  await bootWorkspace({
@@ -8790,7 +8872,7 @@ var init_launch_workspace = __esm({
8790
8872
  });
8791
8873
 
8792
8874
  // packages/core/dist/side-session.js
8793
- import fs14 from "fs";
8875
+ import fs15 from "fs";
8794
8876
  function sideTitleFor(project, name) {
8795
8877
  return `\u{1F5D2} ${project}:${name}`;
8796
8878
  }
@@ -8812,7 +8894,7 @@ function sideNextAutoName(existingTitles, project) {
8812
8894
  i++;
8813
8895
  return `side-${i}`;
8814
8896
  }
8815
- function buildSideFirstTurn(topic, project, role, spokeVault, scratchWorktree) {
8897
+ function buildSideFirstTurn(topic, project, role, workspace, scratchWorktree) {
8816
8898
  const lines = [
8817
8899
  topic,
8818
8900
  "",
@@ -8820,7 +8902,7 @@ function buildSideFirstTurn(topic, project, role, spokeVault, scratchWorktree) {
8820
8902
  "Side-session context (for handoff use):",
8821
8903
  `Project: ${project}`,
8822
8904
  `Role: ${role}`,
8823
- `Spoke vault: ${spokeVault}`
8905
+ `Workspace: ${workspace}`
8824
8906
  ];
8825
8907
  if (scratchWorktree) {
8826
8908
  lines.push(`Scratch worktree: ${scratchWorktree}`);
@@ -8862,7 +8944,7 @@ async function runSideSpawn(input, config, deps) {
8862
8944
  const pane = await runtime.newPane({ workspaceId: captain.id, direction, title });
8863
8945
  await runtime.sendToPane(pane, `cd ${shellQuote(spawnCwd)} && ${SIDE_SESSION_ENV}=1 ${agentCmd}`);
8864
8946
  const preLaunchScreen = await runtime.readPaneScreen(pane) ?? "";
8865
- const firstTurn = buildSideFirstTurn(input.topic, input.project, input.role, proj.spokeVault ?? "", input.role === "debug" ? spawnCwd : void 0);
8947
+ const firstTurn = buildSideFirstTurn(input.topic, input.project, input.role, workspacePath(input.project), input.role === "debug" ? spawnCwd : void 0);
8866
8948
  await deps.sendFirstTurn(pane, spillOversizedFirstTurn(firstTurn, `side-${input.project}-${name}`), preLaunchScreen);
8867
8949
  return { ...pane, title };
8868
8950
  }
@@ -8897,7 +8979,7 @@ async function runSideClose(runtime, workspaceId, project, name, projPath, workt
8897
8979
  }
8898
8980
  if (projPath) {
8899
8981
  const wtPath = worktreePath(projPath, worktreeDir, project, name);
8900
- if (fs14.existsSync(wtPath)) {
8982
+ if (fs15.existsSync(wtPath)) {
8901
8983
  try {
8902
8984
  removeWorktree(projPath, wtPath);
8903
8985
  } catch (e) {
@@ -9411,15 +9493,15 @@ var init_peer_first_turn = __esm({
9411
9493
  });
9412
9494
 
9413
9495
  // packages/core/dist/knowledge/paths.js
9414
- import path15 from "path";
9496
+ import path16 from "path";
9415
9497
  function kbDir(cfg, kb) {
9416
9498
  return kbPath(cfg, kb);
9417
9499
  }
9418
9500
  function kbRulesDir(cfg, kb) {
9419
- return path15.join(kbDir(cfg, kb), "shared", "rules");
9501
+ return path16.join(kbDir(cfg, kb), "shared", "rules");
9420
9502
  }
9421
9503
  function legacyKbDir(hubVault, kb) {
9422
- return path15.join(hubVault, "knowledge", kb);
9504
+ return path16.join(hubVault, "knowledge", kb);
9423
9505
  }
9424
9506
  var PROPOSED_DIR;
9425
9507
  var init_paths = __esm({
@@ -9431,28 +9513,28 @@ var init_paths = __esm({
9431
9513
 
9432
9514
  // packages/core/dist/knowledge/ingest.js
9433
9515
  import crypto3 from "crypto";
9434
- import fs15 from "fs";
9435
- import os7 from "os";
9436
- import path16 from "path";
9516
+ import fs16 from "fs";
9517
+ import os8 from "os";
9518
+ import path17 from "path";
9437
9519
  import { execFile as execFile2 } from "child_process";
9438
9520
  import { promisify as promisify2 } from "util";
9439
9521
  function refFor(kbRoot, file) {
9440
- const rel = path16.relative(kbRoot, file);
9441
- if (rel && !rel.startsWith("..") && !path16.isAbsolute(rel))
9442
- return rel.split(path16.sep).join("/");
9443
- const home = os7.homedir();
9444
- return file.startsWith(home + path16.sep) ? `~/${path16.relative(home, file).split(path16.sep).join("/")}` : file;
9522
+ const rel = path17.relative(kbRoot, file);
9523
+ if (rel && !rel.startsWith("..") && !path17.isAbsolute(rel))
9524
+ return rel.split(path17.sep).join("/");
9525
+ const home = os8.homedir();
9526
+ return file.startsWith(home + path17.sep) ? `~/${path17.relative(home, file).split(path17.sep).join("/")}` : file;
9445
9527
  }
9446
9528
  function readState2(kbRoot, ref) {
9447
9529
  try {
9448
- return JSON.parse(fs15.readFileSync(stampFile(kbRoot, ref), "utf8"));
9530
+ return JSON.parse(fs16.readFileSync(stampFile(kbRoot, ref), "utf8"));
9449
9531
  } catch {
9450
9532
  return null;
9451
9533
  }
9452
9534
  }
9453
9535
  function writeState(kbRoot, st) {
9454
- fs15.mkdirSync(path16.join(kbRoot, CONVERTED_DIR), { recursive: true });
9455
- fs15.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
9536
+ fs16.mkdirSync(path17.join(kbRoot, CONVERTED_DIR), { recursive: true });
9537
+ fs16.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
9456
9538
  }
9457
9539
  function globToRegExp(glob) {
9458
9540
  let re = "";
@@ -9472,12 +9554,12 @@ function globToRegExp(glob) {
9472
9554
  return new RegExp(`^${re}$`);
9473
9555
  }
9474
9556
  function walkFiles(dir, out = []) {
9475
- if (!fs15.existsSync(dir))
9557
+ if (!fs16.existsSync(dir))
9476
9558
  return out;
9477
- for (const ent of fs15.readdirSync(dir, { withFileTypes: true })) {
9559
+ for (const ent of fs16.readdirSync(dir, { withFileTypes: true })) {
9478
9560
  if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
9479
9561
  continue;
9480
- const full = path16.join(dir, ent.name);
9562
+ const full = path17.join(dir, ent.name);
9481
9563
  if (ent.isDirectory())
9482
9564
  walkFiles(full, out);
9483
9565
  else if (ent.isFile())
@@ -9486,27 +9568,27 @@ function walkFiles(dir, out = []) {
9486
9568
  return out;
9487
9569
  }
9488
9570
  function expandSource(kbRoot, entry) {
9489
- const abs = path16.resolve(kbRoot, expandHome(entry.path));
9571
+ const abs = path17.resolve(kbRoot, expandHome(entry.path));
9490
9572
  if (!/[*?]/.test(entry.path))
9491
- return fs15.existsSync(abs) && fs15.statSync(abs).isFile() ? [abs] : [];
9573
+ return fs16.existsSync(abs) && fs16.statSync(abs).isFile() ? [abs] : [];
9492
9574
  const base = abs.split(/[*?]/)[0];
9493
- const root = base.endsWith(path16.sep) ? base : path16.dirname(base);
9494
- const re = globToRegExp(abs.split(path16.sep).join("/"));
9495
- return walkFiles(root).filter((f) => re.test(f.split(path16.sep).join("/"))).sort();
9575
+ const root = base.endsWith(path17.sep) ? base : path17.dirname(base);
9576
+ const re = globToRegExp(abs.split(path17.sep).join("/"));
9577
+ return walkFiles(root).filter((f) => re.test(f.split(path17.sep).join("/"))).sort();
9496
9578
  }
9497
9579
  function refCandidates(kbRoot, sources, ref) {
9498
- const asIs = path16.resolve(kbRoot, expandHome(ref));
9499
- if (path16.isAbsolute(expandHome(ref)))
9580
+ const asIs = path17.resolve(kbRoot, expandHome(ref));
9581
+ if (path17.isAbsolute(expandHome(ref)))
9500
9582
  return [asIs];
9501
9583
  const bases = /* @__PURE__ */ new Set([kbRoot]);
9502
9584
  for (const s of sources) {
9503
- let d = path16.resolve(kbRoot, expandHome(s.path.split(/[*?[{]/)[0]));
9504
- for (let i = 0; i < 6 && d !== path16.dirname(d); i++) {
9505
- d = path16.dirname(d);
9585
+ let d = path17.resolve(kbRoot, expandHome(s.path.split(/[*?[{]/)[0]));
9586
+ for (let i = 0; i < 6 && d !== path17.dirname(d); i++) {
9587
+ d = path17.dirname(d);
9506
9588
  bases.add(d);
9507
9589
  }
9508
9590
  }
9509
- return [.../* @__PURE__ */ new Set([asIs, ...[...bases].map((b) => path16.join(b, ref))])];
9591
+ return [.../* @__PURE__ */ new Set([asIs, ...[...bases].map((b) => path17.join(b, ref))])];
9510
9592
  }
9511
9593
  function refPath(kbRoot, sources, ref) {
9512
9594
  const cands = refCandidates(kbRoot, sources, ref);
@@ -9525,7 +9607,7 @@ function refCanon(kbRoot, sources) {
9525
9607
  }
9526
9608
  function detectChange(kbRoot, file) {
9527
9609
  const ref = refFor(kbRoot, file);
9528
- const st = fs15.statSync(file);
9610
+ const st = fs16.statSync(file);
9529
9611
  const prior = readState2(kbRoot, ref);
9530
9612
  if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
9531
9613
  return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
@@ -9582,13 +9664,13 @@ async function planIngest(kbRoot, opts) {
9582
9664
  let text;
9583
9665
  const conv = convertedFile(kbRoot, ref);
9584
9666
  try {
9585
- if (!changed && fs15.existsSync(conv))
9586
- text = fs15.readFileSync(conv, "utf8");
9667
+ if (!changed && fs16.existsSync(conv))
9668
+ text = fs16.readFileSync(conv, "utf8");
9587
9669
  else {
9588
- text = PASS_THROUGH.has(path16.extname(file).toLowerCase()) ? fs15.readFileSync(file, "utf8") : await converter(file);
9670
+ text = PASS_THROUGH.has(path17.extname(file).toLowerCase()) ? fs16.readFileSync(file, "utf8") : await converter(file);
9589
9671
  if (!opts.dryRun) {
9590
- fs15.mkdirSync(path16.dirname(conv), { recursive: true });
9591
- fs15.writeFileSync(conv, text);
9672
+ fs16.mkdirSync(path17.dirname(conv), { recursive: true });
9673
+ fs16.writeFileSync(conv, text);
9592
9674
  }
9593
9675
  }
9594
9676
  } catch (e) {
@@ -9632,19 +9714,19 @@ var init_ingest = __esm({
9632
9714
  const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
9633
9715
  return stdout;
9634
9716
  };
9635
- expandHome = (p) => p === "~" || p.startsWith("~/") ? path16.join(os7.homedir(), p.slice(1)) : p;
9717
+ expandHome = (p) => p === "~" || p.startsWith("~/") ? path17.join(os8.homedir(), p.slice(1)) : p;
9636
9718
  cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
9637
- convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
9638
- stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
9639
- isFile = (f) => fs15.existsSync(f) && fs15.statSync(f).isFile();
9719
+ convertedFile = (kbRoot, ref) => path17.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
9720
+ stampFile = (kbRoot, ref) => path17.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
9721
+ isFile = (f) => fs16.existsSync(f) && fs16.statSync(f).isFile();
9640
9722
  resolveSourceRef = (kbRoot, sources, ref) => refCandidates(kbRoot, sources, ref).find(isFile);
9641
9723
  entryCovers = (kbRoot, entry, file) => {
9642
- const abs = path16.resolve(kbRoot, expandHome(entry.path));
9643
- return /[*?]/.test(entry.path) ? globToRegExp(abs.split(path16.sep).join("/")).test(file.split(path16.sep).join("/")) : abs === file;
9724
+ const abs = path17.resolve(kbRoot, expandHome(entry.path));
9725
+ return /[*?]/.test(entry.path) ? globToRegExp(abs.split(path17.sep).join("/")).test(file.split(path17.sep).join("/")) : abs === file;
9644
9726
  };
9645
9727
  sourceCovers = (kbRoot, sources, entry, ref) => entryCovers(kbRoot, entry, refPath(kbRoot, sources, ref));
9646
9728
  isGatedRef = (kbRoot, sources, ref) => sources.some((e) => e.review === "required" && sourceCovers(kbRoot, sources, e, ref));
9647
- sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
9729
+ sha256 = (file) => crypto3.createHash("sha256").update(fs16.readFileSync(file)).digest("hex");
9648
9730
  }
9649
9731
  });
9650
9732
 
@@ -9725,14 +9807,14 @@ var init_verify = __esm({
9725
9807
  });
9726
9808
 
9727
9809
  // packages/core/dist/knowledge/store.js
9728
- import fs16 from "fs";
9729
- import path17 from "path";
9810
+ import fs17 from "fs";
9811
+ import path18 from "path";
9730
9812
  import matter2 from "gray-matter";
9731
9813
  function duplicateIdProblem(id, ignored, used) {
9732
9814
  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.`;
9733
9815
  }
9734
9816
  function isPendingProposalDup(e, rulesDir) {
9735
- return e.problems.every((p) => p.startsWith("duplicate id")) && path17.relative(rulesDir, e.file).split(path17.sep).includes(PROPOSED_DIR);
9817
+ return e.problems.every((p) => p.startsWith("duplicate id")) && path18.relative(rulesDir, e.file).split(path18.sep).includes(PROPOSED_DIR);
9736
9818
  }
9737
9819
  function splitStatement(body) {
9738
9820
  const first = body.trim().split(/\n\s*\n/)[0] ?? "";
@@ -9741,8 +9823,8 @@ function splitStatement(body) {
9741
9823
  function listMarkdown(dir, includeProposed) {
9742
9824
  const out = [];
9743
9825
  const walk = (d) => {
9744
- for (const ent of fs16.readdirSync(d, { withFileTypes: true })) {
9745
- const full = path17.join(d, ent.name);
9826
+ for (const ent of fs17.readdirSync(d, { withFileTypes: true })) {
9827
+ const full = path18.join(d, ent.name);
9746
9828
  if (ent.isDirectory()) {
9747
9829
  if (ent.name === PROPOSED_DIR && !includeProposed)
9748
9830
  continue;
@@ -9753,11 +9835,11 @@ function listMarkdown(dir, includeProposed) {
9753
9835
  }
9754
9836
  };
9755
9837
  walk(dir);
9756
- const isProposed = (f) => path17.relative(dir, f).split(path17.sep).includes(PROPOSED_DIR);
9838
+ const isProposed = (f) => path18.relative(dir, f).split(path18.sep).includes(PROPOSED_DIR);
9757
9839
  return out.sort((a, b) => Number(isProposed(a)) - Number(isProposed(b)) || (a < b ? -1 : a > b ? 1 : 0));
9758
9840
  }
9759
9841
  function loadRulesDir(dir, layer, opts = {}) {
9760
- if (!fs16.existsSync(dir))
9842
+ if (!fs17.existsSync(dir))
9761
9843
  return { rules: [], errors: [] };
9762
9844
  const rules = [];
9763
9845
  const errors = [];
@@ -9765,7 +9847,7 @@ function loadRulesDir(dir, layer, opts = {}) {
9765
9847
  for (const file of listMarkdown(dir, opts.includeProposed ?? false)) {
9766
9848
  let parsed;
9767
9849
  try {
9768
- parsed = matter2(fs16.readFileSync(file, "utf8"), NO_JS_FRONTMATTER);
9850
+ parsed = matter2(fs17.readFileSync(file, "utf8"), NO_JS_FRONTMATTER);
9769
9851
  } catch (e) {
9770
9852
  errors.push({ file, problems: [`frontmatter parse error: ${e.message}`] });
9771
9853
  continue;
@@ -9792,7 +9874,7 @@ function validateKb(opts) {
9792
9874
  const dups = errors.filter((e) => e.problems.some((p) => p.startsWith("duplicate id")) && !isPendingProposalDup(e, opts.rulesDir));
9793
9875
  const pendingDups = errors.filter((e) => isPendingProposalDup(e, opts.rulesDir)).length;
9794
9876
  const invalid = errors.filter((e) => !dups.includes(e) && !isPendingProposalDup(e, opts.rulesDir));
9795
- const proposed = rules.filter((r) => path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR)).length;
9877
+ const proposed = rules.filter((r) => path18.relative(opts.rulesDir, r.file).split(path18.sep).includes(PROPOSED_DIR)).length;
9796
9878
  checks.push({ level: "ok", message: `${rules.length + errors.length} rule files read (${rules.length - proposed} live, ${proposed + pendingDups} proposed parsed OK)` });
9797
9879
  if (invalid.length)
9798
9880
  for (const e of invalid)
@@ -9817,17 +9899,17 @@ function validateKb(opts) {
9817
9899
  const key = `${src.ref}\0${file}`;
9818
9900
  if (!cache.has(key)) {
9819
9901
  const conv = readState2(opts.kbRoot, canon(src.ref)) ? convertedFile(opts.kbRoot, canon(src.ref)) : null;
9820
- const cached = !!conv && fs16.existsSync(conv);
9902
+ const cached = !!conv && fs17.existsSync(conv);
9821
9903
  cache.set(key, {
9822
- hay: normalizedViews(fs16.readFileSync(cached ? conv : file, "utf8")),
9823
- convertible: !cached && !PASS_THROUGH.has(path17.extname(file).toLowerCase())
9904
+ hay: normalizedViews(fs17.readFileSync(cached ? conv : file, "utf8")),
9905
+ convertible: !cached && !PASS_THROUGH.has(path18.extname(file).toLowerCase())
9824
9906
  });
9825
9907
  }
9826
9908
  const { hay, convertible } = cache.get(key);
9827
9909
  const span = findQuote(hay, src.quote);
9828
9910
  if (span) {
9829
9911
  verified++;
9830
- const active = r.status === "active" && !path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR);
9912
+ const active = r.status === "active" && !path18.relative(opts.rulesDir, r.file).split(path18.sep).includes(PROPOSED_DIR);
9831
9913
  const err = active ? (opts.errata ?? []).find((e) => canon(e.ref) === canon(src.ref) && ((o) => !!o && spansOverlap(o, span))(findQuote(hay, e.quote))) : void 0;
9832
9914
  if (err)
9833
9915
  checks.push({ level: "warn", message: `${r.id}: grounded in erratum ${err.id} (${err.reason}); re-check or retire it (${r.file})` });
@@ -9867,7 +9949,7 @@ var init_store2 = __esm({
9867
9949
  });
9868
9950
 
9869
9951
  // packages/core/dist/knowledge/layers.js
9870
- import fs17 from "fs";
9952
+ import fs18 from "fs";
9871
9953
  function loadKbRules(cfg, kb, opts = {}) {
9872
9954
  return loadRulesDir(kbRulesDir(cfg, kb), `kb:${kb}`, opts);
9873
9955
  }
@@ -9879,7 +9961,7 @@ function resolveProjectRules(cfg, project, opts = {}) {
9879
9961
  const errors = [];
9880
9962
  const warnings = [];
9881
9963
  for (const kb of subscribedKbs(cfg, project)) {
9882
- if (!fs17.existsSync(kbDir(cfg, kb))) {
9964
+ if (!fs18.existsSync(kbDir(cfg, kb))) {
9883
9965
  warnings.push(`knowledge base '${kb}' not found (run: squadrant knowledge init ${kb})`);
9884
9966
  continue;
9885
9967
  }
@@ -9917,8 +9999,8 @@ var init_layers = __esm({
9917
9999
  });
9918
10000
 
9919
10001
  // packages/core/dist/knowledge/index-file.js
9920
- import fs18 from "fs";
9921
- import path18 from "path";
10002
+ import fs19 from "fs";
10003
+ import path19 from "path";
9922
10004
  function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
9923
10005
  return {
9924
10006
  kb,
@@ -9927,18 +10009,18 @@ function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
9927
10009
  };
9928
10010
  }
9929
10011
  function writeIndex(kbRoot, index) {
9930
- const file = path18.join(kbRoot, "index.json");
10012
+ const file = path19.join(kbRoot, "index.json");
9931
10013
  const tmp = `${file}.tmp-${process.pid}`;
9932
- fs18.writeFileSync(tmp, JSON.stringify(index, null, 2) + "\n");
9933
- fs18.renameSync(tmp, file);
10014
+ fs19.writeFileSync(tmp, JSON.stringify(index, null, 2) + "\n");
10015
+ fs19.renameSync(tmp, file);
9934
10016
  return file;
9935
10017
  }
9936
10018
  function readIndex(kbRoot, kb) {
9937
- const file = path18.join(kbRoot, "index.json");
9938
- if (!fs18.existsSync(file))
10019
+ const file = path19.join(kbRoot, "index.json");
10020
+ if (!fs19.existsSync(file))
9939
10021
  return { index: null, problem: `index.json missing for kb '${kb}'` };
9940
10022
  try {
9941
- const index = JSON.parse(fs18.readFileSync(file, "utf8"));
10023
+ const index = JSON.parse(fs19.readFileSync(file, "utf8"));
9942
10024
  if (!Array.isArray(index.rules))
9943
10025
  return { index: null, problem: `index.json corrupt for kb '${kb}' (no rules array)` };
9944
10026
  return { index };
@@ -13033,16 +13115,16 @@ var init_js_yaml = __esm({
13033
13115
  });
13034
13116
 
13035
13117
  // packages/core/dist/knowledge/sources.js
13036
- import fs19 from "fs";
13037
- import path19 from "path";
13118
+ import fs20 from "fs";
13119
+ import path20 from "path";
13038
13120
  import matter3 from "gray-matter";
13039
13121
  function loadSources(kbRoot) {
13040
- const file = path19.join(kbRoot, "sources.yaml");
13041
- if (!fs19.existsSync(file))
13122
+ const file = path20.join(kbRoot, "sources.yaml");
13123
+ if (!fs20.existsSync(file))
13042
13124
  return { sources: [], errors: [] };
13043
13125
  let data;
13044
13126
  try {
13045
- data = yaml.load(fs19.readFileSync(file, "utf8"));
13127
+ data = yaml.load(fs20.readFileSync(file, "utf8"));
13046
13128
  } catch (e) {
13047
13129
  return { sources: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
13048
13130
  }
@@ -13074,12 +13156,12 @@ function dropEntryBlock(text, entryPath) {
13074
13156
  return [...lines.slice(0, i), ...lines.slice(j)].join("\n");
13075
13157
  }
13076
13158
  function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
13077
- const file = path19.join(kbRoot, "sources.yaml");
13159
+ const file = path20.join(kbRoot, "sources.yaml");
13078
13160
  const { sources } = loadSources(kbRoot);
13079
13161
  const entry = sources.find((s) => s.path === entryPath);
13080
13162
  if (!entry)
13081
13163
  throw new Error(`no sources.yaml entry with path '${entryPath}' (give it exactly as listed by \`knowledge sources\`)`);
13082
- const edited = dropEntryBlock(fs19.readFileSync(file, "utf8"), entryPath);
13164
+ const edited = dropEntryBlock(fs20.readFileSync(file, "utf8"), entryPath);
13083
13165
  if (edited === null)
13084
13166
  throw new Error(`could not edit sources.yaml for '${entryPath}' (not a plain block entry); remove it by hand, then rerun to strip the refs`);
13085
13167
  const res = { dryRun: !!opts.dryRun, entryRemoved: true, stripped: [], stale: [] };
@@ -13089,7 +13171,7 @@ function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
13089
13171
  if (kept.length === rule.sources.length)
13090
13172
  continue;
13091
13173
  res.stripped.push(rule.id);
13092
- const parsed = matter3(fs19.readFileSync(rule.file, "utf8"), { engines: { javascript: () => {
13174
+ const parsed = matter3(fs20.readFileSync(rule.file, "utf8"), { engines: { javascript: () => {
13093
13175
  throw new Error("only YAML front matter is allowed");
13094
13176
  } } });
13095
13177
  const fm = { ...parsed.data, sources: kept };
@@ -13105,9 +13187,9 @@ function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
13105
13187
  if (opts.dryRun)
13106
13188
  return res;
13107
13189
  for (const w of writes)
13108
- fs19.writeFileSync(w.file, w.text);
13109
- fs19.writeFileSync(file, edited);
13110
- const name = opts.kbName ?? path19.basename(kbRoot);
13190
+ fs20.writeFileSync(w.file, w.text);
13191
+ fs20.writeFileSync(file, edited);
13192
+ const name = opts.kbName ?? path20.basename(kbRoot);
13111
13193
  writeIndex(kbRoot, compileIndex(name, loadRulesDir(rulesDir, `kb:${name}`).rules));
13112
13194
  return res;
13113
13195
  }
@@ -13138,25 +13220,25 @@ var init_sources = __esm({
13138
13220
  });
13139
13221
 
13140
13222
  // packages/core/dist/knowledge/match.js
13141
- import path20 from "path";
13223
+ import path21 from "path";
13142
13224
  function globMatches(glob, relPath) {
13143
13225
  const g = glob.replace(/^\.\//, "");
13144
13226
  if (globToRegExp(g).test(relPath))
13145
13227
  return true;
13146
- return !g.includes("/") && globToRegExp(g).test(path20.posix.basename(relPath));
13228
+ return !g.includes("/") && globToRegExp(g).test(path21.posix.basename(relPath));
13147
13229
  }
13148
13230
  function repoRelativePaths(file, cwd, projectRoot) {
13149
13231
  const out = /* @__PURE__ */ new Set();
13150
13232
  const add = (base) => {
13151
- const rel = path20.relative(base, file).split(path20.sep).join("/");
13152
- if (!rel || rel.startsWith("..") || path20.isAbsolute(rel))
13233
+ const rel = path21.relative(base, file).split(path21.sep).join("/");
13234
+ if (!rel || rel.startsWith("..") || path21.isAbsolute(rel))
13153
13235
  return;
13154
13236
  out.add(rel);
13155
13237
  const wt = /^\.worktrees\/[^/]+\/(.+)$/.exec(rel);
13156
13238
  if (wt)
13157
13239
  out.add(wt[1]);
13158
13240
  };
13159
- if (path20.isAbsolute(file)) {
13241
+ if (path21.isAbsolute(file)) {
13160
13242
  add(cwd);
13161
13243
  add(projectRoot);
13162
13244
  } else
@@ -13205,25 +13287,27 @@ var init_match = __esm({
13205
13287
  });
13206
13288
 
13207
13289
  // packages/core/dist/knowledge/audit.js
13208
- import fs20 from "fs";
13209
- import os8 from "os";
13210
- import path21 from "path";
13290
+ import fs21 from "fs";
13291
+ import os9 from "os";
13292
+ import path22 from "path";
13211
13293
  function appendAudit(events, sink = {}) {
13212
13294
  if (!events.length)
13213
13295
  return;
13214
13296
  try {
13215
13297
  const ts = (sink.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
13298
+ const task = (sink.env ?? process.env).SQUADRANT_CREW_TASK_ID;
13216
13299
  const dir = sink.dir ?? defaultAuditDir();
13217
- const file = path21.join(dir, `${ts.slice(0, 7)}.${sink.machineId ?? auditMachineId()}.jsonl`);
13218
- fs20.mkdirSync(dir, { recursive: true });
13219
- const fd = fs20.openSync(file, "a");
13300
+ const file = path22.join(dir, `${ts.slice(0, 7)}.${sink.machineId ?? auditMachineId()}.jsonl`);
13301
+ fs21.mkdirSync(dir, { recursive: true });
13302
+ const fd = fs21.openSync(file, "a");
13220
13303
  try {
13221
13304
  for (const e of events) {
13222
13305
  const q = e.query === void 0 ? {} : { query: e.query.slice(0, AUDIT_QUERY_CHARS) };
13223
- fs20.writeSync(fd, JSON.stringify({ ts, ...e, ...q }) + "\n");
13306
+ const t = task && e.task === void 0 && DELIVERY_EVENTS.has(e.event) ? { task } : {};
13307
+ fs21.writeSync(fd, JSON.stringify({ ts, ...e, ...q, ...t }) + "\n");
13224
13308
  }
13225
13309
  } finally {
13226
- fs20.closeSync(fd);
13310
+ fs21.closeSync(fd);
13227
13311
  }
13228
13312
  } catch (err) {
13229
13313
  console.error(`squadrant audit: log write failed: ${err.message}`);
@@ -13232,18 +13316,22 @@ function appendAudit(events, sink = {}) {
13232
13316
  function ruleAuditScope(rule) {
13233
13317
  return rule.layer.startsWith("kb:") ? { kb: rule.layer.slice(3), level: "group" } : { kb: "", level: "project" };
13234
13318
  }
13235
- var AUDIT_QUERY_CHARS, defaultAuditDir, auditMachineId;
13319
+ var OUTCOME_SOURCES, outcomeSource, RATED_SOURCES, DELIVERY_EVENTS, AUDIT_QUERY_CHARS, defaultAuditDir, auditMachineId;
13236
13320
  var init_audit = __esm({
13237
13321
  "packages/core/dist/knowledge/audit.js"() {
13322
+ OUTCOME_SOURCES = ["operator", "review", "crew", "reconcile", "judge", "check"];
13323
+ outcomeSource = (e) => typeof e.source === "string" && e.source ? e.source : "operator";
13324
+ RATED_SOURCES = /* @__PURE__ */ new Set(["operator", "review", "judge", "check"]);
13325
+ DELIVERY_EVENTS = /* @__PURE__ */ new Set(["item.surfaced", "item.shown", "item.searched"]);
13238
13326
  AUDIT_QUERY_CHARS = 200;
13239
- defaultAuditDir = () => process.env.SQUADRANT_AUDIT_DIR || path21.join(os8.homedir(), ".local", "state", "squadrant", "audit");
13240
- auditMachineId = () => os8.hostname().replace(/[^A-Za-z0-9_-]/g, "_") || "host";
13327
+ defaultAuditDir = () => process.env.SQUADRANT_AUDIT_DIR || path22.join(os9.homedir(), ".local", "state", "squadrant", "audit");
13328
+ auditMachineId = () => os9.hostname().replace(/[^A-Za-z0-9_-]/g, "_") || "host";
13241
13329
  }
13242
13330
  });
13243
13331
 
13244
13332
  // packages/core/dist/knowledge/inject.js
13245
- import fs21 from "fs";
13246
- import path22 from "path";
13333
+ import fs22 from "fs";
13334
+ import path23 from "path";
13247
13335
  function sessionOrder(a, b) {
13248
13336
  const proj = (r) => r.layer.startsWith("project:") ? 0 : 1;
13249
13337
  const mod = (r) => r.modality === "must-not" ? 0 : 1;
@@ -13317,7 +13405,7 @@ function promptText(prompt) {
13317
13405
  if (!m)
13318
13406
  return prompt;
13319
13407
  try {
13320
- return fs21.readFileSync(m[1], "utf8").slice(0, MAX_PROMPT_CHARS * 2);
13408
+ return fs22.readFileSync(m[1], "utf8").slice(0, MAX_PROMPT_CHARS * 2);
13321
13409
  } catch {
13322
13410
  return prompt;
13323
13411
  }
@@ -13361,39 +13449,39 @@ function rulesFallbackPointer(kbs) {
13361
13449
  "Before changing code, look up the rules that apply with `squadrant rules search <terms>`, then `squadrant rules show <id>`."
13362
13450
  ].join("\n");
13363
13451
  }
13364
- function injectStateDir(stateRoot) {
13365
- return path22.join(stateRoot, "rules-inject");
13452
+ function injectStateDir(stateRoot2) {
13453
+ return path23.join(stateRoot2, "rules-inject");
13366
13454
  }
13367
- function readSeenRules(stateRoot, sessionId) {
13455
+ function readSeenRules(stateRoot2, sessionId) {
13368
13456
  try {
13369
- const ids = JSON.parse(fs21.readFileSync(sessionFile(stateRoot, sessionId), "utf8"));
13457
+ const ids = JSON.parse(fs22.readFileSync(sessionFile(stateRoot2, sessionId), "utf8"));
13370
13458
  return new Set(Array.isArray(ids) ? ids.filter((x) => typeof x === "string") : []);
13371
13459
  } catch {
13372
13460
  return /* @__PURE__ */ new Set();
13373
13461
  }
13374
13462
  }
13375
- function recordSeenRules(stateRoot, sessionId, ids) {
13463
+ function recordSeenRules(stateRoot2, sessionId, ids) {
13376
13464
  if (!ids.length)
13377
13465
  return;
13378
- const seen = readSeenRules(stateRoot, sessionId);
13466
+ const seen = readSeenRules(stateRoot2, sessionId);
13379
13467
  for (const id of ids)
13380
13468
  seen.add(id);
13381
- fs21.mkdirSync(injectStateDir(stateRoot), { recursive: true });
13382
- fs21.writeFileSync(sessionFile(stateRoot, sessionId), JSON.stringify([...seen]));
13469
+ fs22.mkdirSync(injectStateDir(stateRoot2), { recursive: true });
13470
+ fs22.writeFileSync(sessionFile(stateRoot2, sessionId), JSON.stringify([...seen]));
13383
13471
  }
13384
- function pruneSeenRules(stateRoot, now = Date.now()) {
13385
- const dir = injectStateDir(stateRoot);
13472
+ function pruneSeenRules(stateRoot2, now = Date.now()) {
13473
+ const dir = injectStateDir(stateRoot2);
13386
13474
  let names;
13387
13475
  try {
13388
- names = fs21.readdirSync(dir);
13476
+ names = fs22.readdirSync(dir);
13389
13477
  } catch {
13390
13478
  return;
13391
13479
  }
13392
13480
  for (const n of names) {
13393
- const f = path22.join(dir, n);
13481
+ const f = path23.join(dir, n);
13394
13482
  try {
13395
- if (now - fs21.statSync(f).mtimeMs > SEEN_TTL_MS)
13396
- fs21.unlinkSync(f);
13483
+ if (now - fs22.statSync(f).mtimeMs > SEEN_TTL_MS)
13484
+ fs22.unlinkSync(f);
13397
13485
  } catch {
13398
13486
  }
13399
13487
  }
@@ -13402,8 +13490,8 @@ async function withBudget(fn, budgetMs = INJECT_BUDGET_MS) {
13402
13490
  const start = Date.now();
13403
13491
  let timer;
13404
13492
  try {
13405
- const timeout = new Promise((resolve4) => {
13406
- timer = setTimeout(() => resolve4(null), budgetMs);
13493
+ const timeout = new Promise((resolve5) => {
13494
+ timer = setTimeout(() => resolve5(null), budgetMs);
13407
13495
  });
13408
13496
  const out = await Promise.race([Promise.resolve().then(fn), timeout]);
13409
13497
  return Date.now() - start > budgetMs ? null : out;
@@ -13421,7 +13509,7 @@ function resolveInjectProject(cfg, cwd, env, project) {
13421
13509
  let bestLen = -1;
13422
13510
  for (const [name, pc] of Object.entries(cfg.projects)) {
13423
13511
  const root = resolveHome(pc.path);
13424
- if ((cwd === root || cwd.startsWith(root + path22.sep)) && root.length > bestLen) {
13512
+ if ((cwd === root || cwd.startsWith(root + path23.sep)) && root.length > bestLen) {
13425
13513
  best = name;
13426
13514
  bestLen = root.length;
13427
13515
  }
@@ -13440,7 +13528,7 @@ function audit(i, project, session, trigger, items) {
13440
13528
  chars: line(rule).length,
13441
13529
  agent: i.agent ?? "claude",
13442
13530
  ...session ? { session } : {}
13443
- })), i.audit);
13531
+ })), { env: i.env, ...i.audit });
13444
13532
  }
13445
13533
  function computeRulesInjection(i) {
13446
13534
  if (i.env.SQUADRANT_RULES_INJECT === "0")
@@ -13529,23 +13617,23 @@ var init_inject = __esm({
13529
13617
  READ_TOOLS = /* @__PURE__ */ new Set(["read", "read_file", "readfile", "view"]);
13530
13618
  SHELL_TOOLS = /* @__PURE__ */ new Set(["bash", "shell", "run_shell_command", "local_shell", "exec_command"]);
13531
13619
  SHELL_META = /[|;&<>$`()]/;
13532
- sessionFile = (stateRoot, sessionId) => path22.join(injectStateDir(stateRoot), `${sessionId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
13620
+ sessionFile = (stateRoot2, sessionId) => path23.join(injectStateDir(stateRoot2), `${sessionId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
13533
13621
  MAX_SUPPRESSED_LOGGED = 10;
13534
13622
  }
13535
13623
  });
13536
13624
 
13537
13625
  // packages/core/dist/knowledge/migrate.js
13538
- import fs22 from "fs";
13539
- import path23 from "path";
13626
+ import fs23 from "fs";
13627
+ import path24 from "path";
13540
13628
  import { execFileSync as execFileSync6 } from "child_process";
13541
13629
  function findLegacyKbs(cfg) {
13542
13630
  const root = legacyRoot(cfg);
13543
- if (!fs22.existsSync(root))
13631
+ if (!fs23.existsSync(root))
13544
13632
  return [];
13545
- return fs22.readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory() && KB_NAME_RE.test(e.name)).map((e) => e.name).sort();
13633
+ return fs23.readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory() && KB_NAME_RE.test(e.name)).map((e) => e.name).sort();
13546
13634
  }
13547
13635
  function ensureGitRepo(dir) {
13548
- if (fs22.existsSync(path23.join(dir, ".git")))
13636
+ if (fs23.existsSync(path24.join(dir, ".git")))
13549
13637
  return false;
13550
13638
  try {
13551
13639
  execFileSync6("git", ["init", "-q", dir], { stdio: "ignore" });
@@ -13555,14 +13643,14 @@ function ensureGitRepo(dir) {
13555
13643
  }
13556
13644
  }
13557
13645
  function ensureKbGitignore(dir) {
13558
- const file = path23.join(dir, ".gitignore");
13559
- if (fs22.existsSync(file))
13646
+ const file = path24.join(dir, ".gitignore");
13647
+ if (fs23.existsSync(file))
13560
13648
  return false;
13561
- fs22.writeFileSync(file, KB_GITIGNORE);
13649
+ fs23.writeFileSync(file, KB_GITIGNORE);
13562
13650
  return true;
13563
13651
  }
13564
13652
  function findLegacyOverlays(cfg) {
13565
- return Object.keys(cfg.projects).filter((p) => fs22.existsSync(legacyOverlay(cfg, p))).sort();
13653
+ return Object.keys(cfg.projects).filter((p) => fs23.existsSync(legacyOverlay(cfg, p))).sort();
13566
13654
  }
13567
13655
  function moveLegacyOverlays(cfg, opts = {}) {
13568
13656
  return findLegacyOverlays(cfg).map((project) => {
@@ -13571,18 +13659,18 @@ function moveLegacyOverlays(cfg, opts = {}) {
13571
13659
  const kb = `overlay:${project}`;
13572
13660
  if (!to)
13573
13661
  return { kb, from, to: "", action: "skipped", note: "no group KB or knowledgeHome for this project; set one, then re-run" };
13574
- if (fs22.existsSync(to))
13662
+ if (fs23.existsSync(to))
13575
13663
  return { kb, from, to, action: "skipped", note: "target already exists; nothing moved" };
13576
13664
  if (opts.dryRun)
13577
13665
  return { kb, from, to, action: "would-move" };
13578
- fs22.mkdirSync(path23.dirname(to), { recursive: true });
13666
+ fs23.mkdirSync(path24.dirname(to), { recursive: true });
13579
13667
  try {
13580
- fs22.renameSync(from, to);
13668
+ fs23.renameSync(from, to);
13581
13669
  return { kb, from, to, action: "moved" };
13582
13670
  } catch (e) {
13583
13671
  if (e.code !== "EXDEV")
13584
13672
  throw e;
13585
- fs22.cpSync(from, to, { recursive: true });
13673
+ fs23.cpSync(from, to, { recursive: true });
13586
13674
  return { kb, from, to, action: "copied", note: "cross-device: original left in place, delete it yourself once verified" };
13587
13675
  }
13588
13676
  });
@@ -13592,32 +13680,32 @@ function moveLegacyKbs(cfg, opts = {}) {
13592
13680
  return findLegacyKbs(cfg).map((kb) => {
13593
13681
  const from = legacyKbDir(hub, kb);
13594
13682
  const to = kbDir(cfg, kb);
13595
- if (fs22.existsSync(to))
13683
+ if (fs23.existsSync(to))
13596
13684
  return { kb, from, to, action: "skipped", note: "target already exists; nothing moved" };
13597
13685
  if (opts.dryRun)
13598
13686
  return { kb, from, to, action: "would-move" };
13599
- fs22.mkdirSync(path23.dirname(to), { recursive: true });
13687
+ fs23.mkdirSync(path24.dirname(to), { recursive: true });
13600
13688
  let action = "moved";
13601
13689
  try {
13602
- fs22.renameSync(from, to);
13690
+ fs23.renameSync(from, to);
13603
13691
  } catch (e) {
13604
13692
  if (e.code !== "EXDEV")
13605
13693
  throw e;
13606
- fs22.cpSync(from, to, { recursive: true });
13694
+ fs23.cpSync(from, to, { recursive: true });
13607
13695
  action = "copied";
13608
13696
  }
13609
13697
  const notes = [];
13610
- const oldRules = path23.join(to, "rules"), newRules = path23.join(to, "shared", "rules");
13611
- if (fs22.existsSync(oldRules) && !fs22.existsSync(newRules)) {
13612
- fs22.mkdirSync(path23.dirname(newRules), { recursive: true });
13613
- fs22.renameSync(oldRules, newRules);
13698
+ const oldRules = path24.join(to, "rules"), newRules = path24.join(to, "shared", "rules");
13699
+ if (fs23.existsSync(oldRules) && !fs23.existsSync(newRules)) {
13700
+ fs23.mkdirSync(path24.dirname(newRules), { recursive: true });
13701
+ fs23.renameSync(oldRules, newRules);
13614
13702
  notes.push("rules/ -> shared/rules/");
13615
13703
  }
13616
13704
  if (ensureGitRepo(to))
13617
13705
  notes.push("git init");
13618
13706
  if (ensureKbGitignore(to))
13619
13707
  notes.push("wrote .gitignore (raw/, .converted/)");
13620
- if (fs22.existsSync(path23.join(to, "index.json")))
13708
+ if (fs23.existsSync(path24.join(to, "index.json")))
13621
13709
  notes.push(`index.json holds old paths: run squadrant knowledge reindex ${kb}`);
13622
13710
  if (action === "copied")
13623
13711
  notes.push("cross-device: original left in place, delete it yourself once verified");
@@ -13629,22 +13717,22 @@ var init_migrate = __esm({
13629
13717
  "packages/core/dist/knowledge/migrate.js"() {
13630
13718
  init_dist();
13631
13719
  init_paths();
13632
- legacyRoot = (cfg) => path23.join(resolveHome(cfg.hubVault), "knowledge");
13720
+ legacyRoot = (cfg) => path24.join(resolveHome(cfg.hubVault), "knowledge");
13633
13721
  KB_GITIGNORE = "# squadrant KB defaults: source documents stay local\nraw/\n.converted/\n";
13634
- legacyOverlay = (cfg, project) => path23.join(resolveHome(cfg.projects[project].spokeVault), "knowledge", "rules");
13722
+ legacyOverlay = (cfg, project) => path24.join(resolveHome(cfg.projects[project].spokeVault), "knowledge", "rules");
13635
13723
  }
13636
13724
  });
13637
13725
 
13638
13726
  // packages/core/dist/knowledge/errata.js
13639
- import fs23 from "fs";
13640
- import path24 from "path";
13727
+ import fs24 from "fs";
13728
+ import path25 from "path";
13641
13729
  function loadErrata(kbRoot) {
13642
- const file = path24.join(kbRoot, "errata.yaml");
13643
- if (!fs23.existsSync(file))
13730
+ const file = path25.join(kbRoot, "errata.yaml");
13731
+ if (!fs24.existsSync(file))
13644
13732
  return { errata: [], errors: [] };
13645
13733
  let data;
13646
13734
  try {
13647
- data = yaml.load(fs23.readFileSync(file, "utf8"), { schema: yaml.JSON_SCHEMA });
13735
+ data = yaml.load(fs24.readFileSync(file, "utf8"), { schema: yaml.JSON_SCHEMA });
13648
13736
  } catch (e) {
13649
13737
  return { errata: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
13650
13738
  }
@@ -13674,7 +13762,7 @@ function orphanedErrata(kbRoot, sources, errata, refs) {
13674
13762
  continue;
13675
13763
  if (!hays.has(ref)) {
13676
13764
  const conv = readState2(kbRoot, ref) ? convertedFile(kbRoot, ref) : null;
13677
- hays.set(ref, conv && fs23.existsSync(conv) ? normalizedViews(fs23.readFileSync(conv, "utf8")) : null);
13765
+ hays.set(ref, conv && fs24.existsSync(conv) ? normalizedViews(fs24.readFileSync(conv, "utf8")) : null);
13678
13766
  }
13679
13767
  const hay = hays.get(ref);
13680
13768
  if (hay && !findQuote(hay, e.quote))
@@ -13692,9 +13780,9 @@ var init_errata = __esm({
13692
13780
  });
13693
13781
 
13694
13782
  // packages/core/dist/knowledge/anchor.js
13695
- import fs24 from "fs";
13783
+ import fs25 from "fs";
13696
13784
  import { execFileSync as execFileSync7 } from "child_process";
13697
- import path25 from "path";
13785
+ import path26 from "path";
13698
13786
  function gitFiles(root) {
13699
13787
  try {
13700
13788
  const out = execFileSync7("git", ["ls-files", "-co", "--exclude-standard", "-z"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 64 * 1024 * 1024 });
@@ -13708,13 +13796,13 @@ function* repoFiles(root, maxFiles) {
13708
13796
  const listed = gitFiles(root);
13709
13797
  if (listed) {
13710
13798
  for (const rel of listed) {
13711
- if (!CODE_EXT.has(path25.extname(rel)) || rel.split("/").slice(0, -1).some((d) => SKIP_DIRS.has(d)))
13799
+ if (!CODE_EXT.has(path26.extname(rel)) || rel.split("/").slice(0, -1).some((d) => SKIP_DIRS.has(d)))
13712
13800
  continue;
13713
13801
  if (++count > maxFiles) {
13714
13802
  console.warn(`anchor: ${root} has more than ${maxFiles} code files; anchors cover only the first ${maxFiles}`);
13715
13803
  return;
13716
13804
  }
13717
- yield path25.join(root, rel);
13805
+ yield path26.join(root, rel);
13718
13806
  }
13719
13807
  return;
13720
13808
  }
@@ -13723,20 +13811,20 @@ function* repoFiles(root, maxFiles) {
13723
13811
  const dir = stack.pop();
13724
13812
  let ents;
13725
13813
  try {
13726
- ents = fs24.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? 1 : -1);
13814
+ ents = fs25.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? 1 : -1);
13727
13815
  } catch {
13728
13816
  continue;
13729
13817
  }
13730
13818
  for (const ent of ents) {
13731
13819
  if (ent.isDirectory()) {
13732
13820
  if (!SKIP_DIRS.has(ent.name))
13733
- stack.push(path25.join(dir, ent.name));
13734
- } else if (ent.isFile() && CODE_EXT.has(path25.extname(ent.name))) {
13821
+ stack.push(path26.join(dir, ent.name));
13822
+ } else if (ent.isFile() && CODE_EXT.has(path26.extname(ent.name))) {
13735
13823
  if (++count > maxFiles) {
13736
13824
  console.warn(`anchor: ${root} has more than ${maxFiles} code files; anchors cover only the first ${maxFiles}`);
13737
13825
  return;
13738
13826
  }
13739
- yield path25.join(dir, ent.name);
13827
+ yield path26.join(dir, ent.name);
13740
13828
  }
13741
13829
  }
13742
13830
  }
@@ -13745,11 +13833,11 @@ function scanRepo(root, maxFiles) {
13745
13833
  const out = [];
13746
13834
  for (const file of repoFiles(root, maxFiles)) {
13747
13835
  try {
13748
- if (fs24.statSync(file).size > MAX_FILE_BYTES)
13836
+ if (fs25.statSync(file).size > MAX_FILE_BYTES)
13749
13837
  continue;
13750
- const text = fs24.readFileSync(file, "utf8");
13751
- const rel = path25.relative(root, file).split(path25.sep).join("/");
13752
- out.push({ rel, text, hay: `${path25.relative(root, file)}
13838
+ const text = fs25.readFileSync(file, "utf8");
13839
+ const rel = path26.relative(root, file).split(path26.sep).join("/");
13840
+ out.push({ rel, text, hay: `${path26.relative(root, file)}
13753
13841
  ${text}`.toLowerCase() });
13754
13842
  } catch {
13755
13843
  continue;
@@ -13759,7 +13847,7 @@ ${text}`.toLowerCase() });
13759
13847
  }
13760
13848
  function computeAnchor(repoRoot, triggers, cache, maxFiles = MAX_FILES) {
13761
13849
  const terms2 = anchorTerms(triggers);
13762
- if (!terms2.length || !fs24.existsSync(repoRoot))
13850
+ if (!terms2.length || !fs25.existsSync(repoRoot))
13763
13851
  return null;
13764
13852
  let files = cache?.get(repoRoot);
13765
13853
  if (!files) {
@@ -13795,8 +13883,8 @@ var init_anchor = __esm({
13795
13883
  });
13796
13884
 
13797
13885
  // packages/core/dist/knowledge/extract.js
13798
- import fs25 from "fs";
13799
- import path26 from "path";
13886
+ import fs26 from "fs";
13887
+ import path27 from "path";
13800
13888
  import matter4 from "gray-matter";
13801
13889
  function serialize(fm, body) {
13802
13890
  return matter4.stringify(body.trim() + "\n", clean(fm));
@@ -13864,13 +13952,13 @@ function applyCandidates(input, opts) {
13864
13952
  }
13865
13953
  const st = readState2(kbRoot, cand.source);
13866
13954
  const convFile = st ? convertedFile(kbRoot, cand.source) : null;
13867
- if (!st || !fs25.existsSync(convFile)) {
13955
+ if (!st || !fs26.existsSync(convFile)) {
13868
13956
  res.rejected.push({ id: cand.id, source: cand.source, reason: "unknown source (not ingested)" });
13869
13957
  continue;
13870
13958
  }
13871
13959
  let hay = norm.get(cand.source);
13872
13960
  if (!hay) {
13873
- hay = normalizedViews(fs25.readFileSync(convFile, "utf8"));
13961
+ hay = normalizedViews(fs26.readFileSync(convFile, "utf8"));
13874
13962
  norm.set(cand.source, hay);
13875
13963
  }
13876
13964
  const tot = totals.get(cand.source) ?? { total: 0, dropped: 0 };
@@ -13932,7 +14020,7 @@ ${cand.rationale.trim()}` : "");
13932
14020
  supersedes: [],
13933
14021
  conflictsWith: []
13934
14022
  };
13935
- work.set(id, { fm: fm2, body: bodyOf(), file: path26.join(rulesDir, cand.domain, `${id}.md`), dirty: true, isNew: true });
14023
+ work.set(id, { fm: fm2, body: bodyOf(), file: path27.join(rulesDir, cand.domain, `${id}.md`), dirty: true, isNew: true });
13936
14024
  res.created.push(id);
13937
14025
  ev2("item.applied", id);
13938
14026
  continue;
@@ -13949,24 +14037,24 @@ ${cand.rationale.trim()}` : "");
13949
14037
  supersedes: [],
13950
14038
  conflictsWith: contradicted
13951
14039
  };
13952
- const dir = path26.join(rulesDir, PROPOSED_DIR);
13953
- const file = path26.join(dir, `${id}@${st.sha.slice(0, SHA_LEN)}.md`);
14040
+ const dir = path27.join(rulesDir, PROPOSED_DIR);
14041
+ const file = path27.join(dir, `${id}@${st.sha.slice(0, SHA_LEN)}.md`);
13954
14042
  const text = serialize(fm, bodyOf());
13955
- if (fs25.existsSync(file) && fs25.readFileSync(file, "utf8") === text)
14043
+ if (fs26.existsSync(file) && fs26.readFileSync(file, "utf8") === text)
13956
14044
  continue;
13957
- fs25.mkdirSync(dir, { recursive: true });
13958
- for (const other of fs25.readdirSync(dir)) {
13959
- if (!other.startsWith(`${id}@`) || !other.endsWith(".md") || path26.join(dir, other) === file)
14045
+ fs26.mkdirSync(dir, { recursive: true });
14046
+ for (const other of fs26.readdirSync(dir)) {
14047
+ if (!other.startsWith(`${id}@`) || !other.endsWith(".md") || path27.join(dir, other) === file)
13960
14048
  continue;
13961
- const old = matter4(fs25.readFileSync(path26.join(dir, other), "utf8"));
14049
+ const old = matter4(fs26.readFileSync(path27.join(dir, other), "utf8"));
13962
14050
  if (!old.data.sources?.some((s) => canon(s.ref) === canon(cand.source)))
13963
14051
  continue;
13964
- fs25.writeFileSync(path26.join(dir, other.replace(/\.md$/, ".superseded")), matter4.stringify(old.content, { ...old.data, supersededBy: path26.basename(file) }));
13965
- fs25.rmSync(path26.join(dir, other));
14052
+ fs26.writeFileSync(path27.join(dir, other.replace(/\.md$/, ".superseded")), matter4.stringify(old.content, { ...old.data, supersededBy: path27.basename(file) }));
14053
+ fs26.rmSync(path27.join(dir, other));
13966
14054
  res.superseded.push(other.replace(/\.md$/, ""));
13967
14055
  ev2("item.superseded", id);
13968
14056
  }
13969
- fs25.writeFileSync(file, text);
14057
+ fs26.writeFileSync(file, text);
13970
14058
  res.proposed.push(`${id}@${st.sha.slice(0, SHA_LEN)}`);
13971
14059
  ev2("item.proposed", id);
13972
14060
  }
@@ -13995,10 +14083,10 @@ ${cand.rationale.trim()}` : "");
13995
14083
  for (const w of work.values()) {
13996
14084
  if (!w.dirty)
13997
14085
  continue;
13998
- fs25.mkdirSync(path26.dirname(w.file), { recursive: true });
14086
+ fs26.mkdirSync(path27.dirname(w.file), { recursive: true });
13999
14087
  const text = serialize(w.fm, w.body);
14000
- if (!fs25.existsSync(w.file) || fs25.readFileSync(w.file, "utf8") !== text)
14001
- fs25.writeFileSync(w.file, text);
14088
+ if (!fs26.existsSync(w.file) || fs26.readFileSync(w.file, "utf8") !== text)
14089
+ fs26.writeFileSync(w.file, text);
14002
14090
  }
14003
14091
  res.orphanedErrata = orphanedErrata(kbRoot, opts.sources ?? [], opts.errata ?? [], totals.keys());
14004
14092
  for (const [ref, t] of totals)
@@ -14034,20 +14122,20 @@ var init_extract = __esm({
14034
14122
  });
14035
14123
 
14036
14124
  // packages/core/dist/knowledge/schedule.js
14037
- import fs26 from "fs";
14038
- import path27 from "path";
14039
- function readSchedule(stateRoot) {
14125
+ import fs27 from "fs";
14126
+ import path28 from "path";
14127
+ function readSchedule(stateRoot2) {
14040
14128
  try {
14041
- return JSON.parse(fs26.readFileSync(scheduleFile(stateRoot), "utf8"));
14129
+ return JSON.parse(fs27.readFileSync(scheduleFile(stateRoot2), "utf8"));
14042
14130
  } catch {
14043
14131
  return {};
14044
14132
  }
14045
14133
  }
14046
- function writeSchedule(stateRoot, s) {
14047
- fs26.mkdirSync(stateRoot, { recursive: true });
14048
- const tmp = `${scheduleFile(stateRoot)}.${process.pid}.tmp`;
14049
- fs26.writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n");
14050
- fs26.renameSync(tmp, scheduleFile(stateRoot));
14134
+ function writeSchedule(stateRoot2, s) {
14135
+ fs27.mkdirSync(stateRoot2, { recursive: true });
14136
+ const tmp = `${scheduleFile(stateRoot2)}.${process.pid}.tmp`;
14137
+ fs27.writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n");
14138
+ fs27.renameSync(tmp, scheduleFile(stateRoot2));
14051
14139
  }
14052
14140
  function snapshotSources(kbRoot, sources) {
14053
14141
  const out = {};
@@ -14127,7 +14215,7 @@ async function tickKnowledgeSchedule(d) {
14127
14215
  continue;
14128
14216
  try {
14129
14217
  const root = kbDir(d.cfg, kb);
14130
- if (!fs26.existsSync(root))
14218
+ if (!fs27.existsSync(root))
14131
14219
  continue;
14132
14220
  const { sources } = loadSources(root);
14133
14221
  if (!sources.length)
@@ -14192,7 +14280,7 @@ var init_schedule = __esm({
14192
14280
  init_sources();
14193
14281
  RUNNING_STALE_MS = 6 * 60 * 60 * 1e3;
14194
14282
  DAY_MS = 24 * 60 * 60 * 1e3;
14195
- scheduleFile = (stateRoot) => path27.join(stateRoot, "knowledge-schedule.json");
14283
+ scheduleFile = (stateRoot2) => path28.join(stateRoot2, "knowledge-schedule.json");
14196
14284
  reconcileConfig = (cfg, kb) => ({ ...DEFAULT_RECONCILE, ...kbConfigs(cfg)[kb]?.reconcile });
14197
14285
  }
14198
14286
  });
@@ -14200,19 +14288,19 @@ var init_schedule = __esm({
14200
14288
  // packages/core/dist/knowledge/review.js
14201
14289
  import crypto4 from "crypto";
14202
14290
  import { execFileSync as execFileSync8 } from "child_process";
14203
- import fs27 from "fs";
14204
- import path28 from "path";
14291
+ import fs28 from "fs";
14292
+ import path29 from "path";
14205
14293
  import matter5 from "gray-matter";
14206
14294
  function readEscalations(kbRoot) {
14207
14295
  try {
14208
- return JSON.parse(fs27.readFileSync(escalationsFile(kbRoot), "utf8")).items;
14296
+ return JSON.parse(fs28.readFileSync(escalationsFile(kbRoot), "utf8")).items;
14209
14297
  } catch {
14210
14298
  return [];
14211
14299
  }
14212
14300
  }
14213
14301
  function writeEscalations(kbRoot, items) {
14214
- fs27.mkdirSync(kbRoot, { recursive: true });
14215
- fs27.writeFileSync(escalationsFile(kbRoot), JSON.stringify({ items }, null, 2) + "\n");
14302
+ fs28.mkdirSync(kbRoot, { recursive: true });
14303
+ fs28.writeFileSync(escalationsFile(kbRoot), JSON.stringify({ items }, null, 2) + "\n");
14216
14304
  }
14217
14305
  function addEscalation(kbRoot, e) {
14218
14306
  const items = readEscalations(kbRoot);
@@ -14222,8 +14310,8 @@ function addEscalation(kbRoot, e) {
14222
14310
  return true;
14223
14311
  }
14224
14312
  function appendVerdict(kbRoot, v2, now) {
14225
- fs27.mkdirSync(kbRoot, { recursive: true });
14226
- fs27.appendFileSync(verdictsFile(kbRoot), JSON.stringify({ ts: now.toISOString(), ...v2 }) + "\n");
14313
+ fs28.mkdirSync(kbRoot, { recursive: true });
14314
+ fs28.appendFileSync(verdictsFile(kbRoot), JSON.stringify({ ts: now.toISOString(), ...v2 }) + "\n");
14227
14315
  }
14228
14316
  function priorityOfRef(c, ref) {
14229
14317
  if (ref.startsWith("agent:"))
@@ -14240,20 +14328,20 @@ function loadProposals(c) {
14240
14328
  const byId = new Map(live.map((r) => [r.id, r]));
14241
14329
  const proposals = [];
14242
14330
  const pdirs = /* @__PURE__ */ new Set();
14243
- for (const f of fs27.existsSync(dir) ? walkDirs(dir) : [])
14244
- if (path28.basename(f) === PROPOSED_DIR)
14331
+ for (const f of fs28.existsSync(dir) ? walkDirs(dir) : [])
14332
+ if (path29.basename(f) === PROPOSED_DIR)
14245
14333
  pdirs.add(f);
14246
14334
  for (const pd of pdirs) {
14247
14335
  for (const rule of loadRulesDir(pd, `kb:${c.kb}`, { includeProposed: true }).rules) {
14248
- proposals.push({ key: path28.basename(rule.file).replace(/\.md$/, ""), rule, live: byId.get(rule.id) });
14336
+ proposals.push({ key: path29.basename(rule.file).replace(/\.md$/, ""), rule, live: byId.get(rule.id) });
14249
14337
  }
14250
14338
  }
14251
14339
  return { proposals, live };
14252
14340
  }
14253
14341
  function walkDirs(dir, out = []) {
14254
- for (const e of fs27.readdirSync(dir, { withFileTypes: true }))
14342
+ for (const e of fs28.readdirSync(dir, { withFileTypes: true }))
14255
14343
  if (e.isDirectory()) {
14256
- const f = path28.join(dir, e.name);
14344
+ const f = path29.join(dir, e.name);
14257
14345
  out.push(f);
14258
14346
  walkDirs(f, out);
14259
14347
  }
@@ -14282,7 +14370,7 @@ function promoteProposal(c, p, by, justification, events) {
14282
14370
  continue;
14283
14371
  const o = readFm(other.file);
14284
14372
  o.fm.status = "retired";
14285
- fs27.writeFileSync(other.file, fileText(o.fm, o.body));
14373
+ fs28.writeFileSync(other.file, fileText(o.fm, o.body));
14286
14374
  retired.push(id);
14287
14375
  events.push(ev(c, "item.superseded", id));
14288
14376
  }
@@ -14292,16 +14380,16 @@ function promoteProposal(c, p, by, justification, events) {
14292
14380
  const anchors = anchorsFor(c, { ...next, anchors: p.live?.anchors ?? fm.anchors });
14293
14381
  if (anchors)
14294
14382
  next.anchors = anchors;
14295
- const target = p.live?.file ?? path28.join(dir, next.domain, `${next.id}.md`);
14296
- fs27.mkdirSync(path28.dirname(target), { recursive: true });
14297
- fs27.writeFileSync(target, fileText(next, body));
14298
- fs27.rmSync(p.rule.file);
14383
+ const target = p.live?.file ?? path29.join(dir, next.domain, `${next.id}.md`);
14384
+ fs28.mkdirSync(path29.dirname(target), { recursive: true });
14385
+ fs28.writeFileSync(target, fileText(next, body));
14386
+ fs28.rmSync(p.rule.file);
14299
14387
  events.push(ev(c, "item.approved", next.id), ev(c, "item.applied", next.id));
14300
14388
  if (p.live)
14301
14389
  events.push(ev(c, "item.superseded", next.id));
14302
14390
  }
14303
14391
  function dropProposal(c, p, events) {
14304
- fs27.rmSync(p.rule.file);
14392
+ fs28.rmSync(p.rule.file);
14305
14393
  events.push(ev(c, "item.rejected", p.rule.id, { reason: "reviewer" }));
14306
14394
  }
14307
14395
  function mergeInto(c, p, targetId, live, events) {
@@ -14313,8 +14401,8 @@ function mergeInto(c, p, targetId, live, events) {
14313
14401
  for (const s of p.rule.sources)
14314
14402
  if (!tf.fm.sources.some((x) => canon(x.ref) === canon(s.ref)))
14315
14403
  tf.fm.sources.push(s);
14316
- fs27.writeFileSync(t.file, fileText(tf.fm, tf.body));
14317
- fs27.rmSync(p.rule.file);
14404
+ fs28.writeFileSync(t.file, fileText(tf.fm, tf.body));
14405
+ fs28.rmSync(p.rule.file);
14318
14406
  events.push(ev(c, "item.superseded", p.rule.id), ev(c, "item.applied", targetId));
14319
14407
  return true;
14320
14408
  }
@@ -14374,6 +14462,7 @@ function applyDecisions(file, c) {
14374
14462
  if (v2.action === "flag-violation") {
14375
14463
  escalate({ key: `violation:${target.id}`, kind: "code-violation", ruleId: target.id, reasons: ["doc newer than code"], explanation: v2.explanation, needsYou: false });
14376
14464
  res.violations.push(target.id);
14465
+ events.push(ev(c, "item.outcome", target.id, { outcome: "violated", source: "reconcile", project: d.codeConflict.project }));
14377
14466
  } else if (v2.action === "escalate") {
14378
14467
  escalate({ key: `code-vs-doc:${target.id}`, kind: "code-vs-doc", ruleId: target.id, reasons: ["code-vs-doc"], explanation: v2.explanation, evidence: v2.evidence, confidence: conf });
14379
14468
  verdict(d, "escalated", { reasons: ["code-vs-doc"], confidence: conf });
@@ -14392,7 +14481,7 @@ function applyDecisions(file, c) {
14392
14481
  f.fm.sources[0].loc = d.loc;
14393
14482
  const noSource = !rule.sources.length;
14394
14483
  if (conf >= threshold && !d.flag && !reasons.length && !noSource) {
14395
- fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
14484
+ fs28.writeFileSync(rule.file, fileText(f.fm, f.body));
14396
14485
  res.applied.push(d.item);
14397
14486
  events.push(ev(c, "item.applied", rule.id));
14398
14487
  verdict(d, "applied", { confidence: conf });
@@ -14409,7 +14498,7 @@ function applyDecisions(file, c) {
14409
14498
  if (!reasons.length) {
14410
14499
  const f = readFm(rule.file);
14411
14500
  f.fm.status = "retired";
14412
- fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
14501
+ fs28.writeFileSync(rule.file, fileText(f.fm, f.body));
14413
14502
  res.applied.push(d.item);
14414
14503
  events.push(ev(c, "item.archived", rule.id));
14415
14504
  verdict(d, "applied", { confidence: conf });
@@ -14489,7 +14578,7 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
14489
14578
  for (const [x, y] of [[a, b], [b, a]]) {
14490
14579
  const f = readFm(x.file);
14491
14580
  f.fm.conflictsWith = [.../* @__PURE__ */ new Set([...f.fm.conflictsWith ?? [], y.id])];
14492
- fs27.writeFileSync(x.file, fileText(f.fm, f.body));
14581
+ fs28.writeFileSync(x.file, fileText(f.fm, f.body));
14493
14582
  }
14494
14583
  return;
14495
14584
  }
@@ -14505,10 +14594,10 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
14505
14594
  if (!kf.fm.sources.some((x) => canon(x.ref) === canon(s.ref)))
14506
14595
  kf.fm.sources.push(s);
14507
14596
  kf.fm.supersedes = [.../* @__PURE__ */ new Set([...kf.fm.supersedes ?? [], drop.id])];
14508
- fs27.writeFileSync(keep.file, fileText(kf.fm, kf.body));
14597
+ fs28.writeFileSync(keep.file, fileText(kf.fm, kf.body));
14509
14598
  const df = readFm(drop.file);
14510
14599
  df.fm.status = "retired";
14511
- fs27.writeFileSync(drop.file, fileText(df.fm, df.body));
14600
+ fs28.writeFileSync(drop.file, fileText(df.fm, df.body));
14512
14601
  events.push(ev(c, "item.superseded", drop.id), ev(c, "item.applied", keep.id));
14513
14602
  res.applied.push(key);
14514
14603
  }
@@ -14541,7 +14630,7 @@ function resolveEscalation(c, key, r, by, reason) {
14541
14630
  f.fm.status = "retired";
14542
14631
  events.push(ev(c, "item.superseded", rule.id));
14543
14632
  }
14544
- fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
14633
+ fs28.writeFileSync(rule.file, fileText(f.fm, f.body));
14545
14634
  return done(`${rule.id}: ${r.verdict}`);
14546
14635
  }
14547
14636
  if (esc.kind === "proposal") {
@@ -14564,20 +14653,20 @@ function resolveEscalation(c, key, r, by, reason) {
14564
14653
  if (rule) {
14565
14654
  const f = readFm(rule.file);
14566
14655
  f.fm.status = r.kind === "approve" ? "retired" : "active";
14567
- fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
14656
+ fs28.writeFileSync(rule.file, fileText(f.fm, f.body));
14568
14657
  events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule.id));
14569
14658
  }
14570
14659
  return done(`${esc.ruleId}: ${r.kind === "approve" ? "retired" : "kept"}`);
14571
14660
  }
14572
14661
  if (esc.kind === "override-base-changed") {
14573
- const ov = esc.item && fs27.existsSync(esc.item) ? esc.item : void 0;
14662
+ const ov = esc.item && fs28.existsSync(esc.item) ? esc.item : void 0;
14574
14663
  if (ov) {
14575
14664
  if (r.kind === "reject")
14576
- fs27.rmSync(ov);
14665
+ fs28.rmSync(ov);
14577
14666
  else {
14578
14667
  const f = readFm(ov);
14579
14668
  f.fm.overridesBase = esc.evidence?.docRev;
14580
- fs27.writeFileSync(ov, fileText(f.fm, f.body));
14669
+ fs28.writeFileSync(ov, fileText(f.fm, f.body));
14581
14670
  }
14582
14671
  }
14583
14672
  return done(`${esc.ruleId}: override ${r.kind === "reject" ? "dropped" : "kept"}`);
@@ -14601,10 +14690,10 @@ ${o.evidence}`).digest("hex");
14601
14690
  supersedes: [],
14602
14691
  conflictsWith: []
14603
14692
  };
14604
- const dir = path28.join(kbRulesDir(c.cfg, c.kb), PROPOSED_DIR);
14605
- fs27.mkdirSync(dir, { recursive: true });
14606
- const file = path28.join(dir, `${id}@${sha.slice(0, SHA_LEN2)}.md`);
14607
- fs27.writeFileSync(file, fileText(fm, o.statement));
14693
+ const dir = path29.join(kbRulesDir(c.cfg, c.kb), PROPOSED_DIR);
14694
+ fs28.mkdirSync(dir, { recursive: true });
14695
+ const file = path29.join(dir, `${id}@${sha.slice(0, SHA_LEN2)}.md`);
14696
+ fs28.writeFileSync(file, fileText(fm, o.statement));
14608
14697
  appendAudit([ev(c, "item.proposed", id)], c.audit);
14609
14698
  return file;
14610
14699
  }
@@ -14645,8 +14734,8 @@ var init_review = __esm({
14645
14734
  PRIORITY_RANK = { company: 3, project: 2, agent: 1 };
14646
14735
  SHA_LEN2 = 12;
14647
14736
  strong = (m) => m === "must" || m === "must-not";
14648
- escalationsFile = (kbRoot) => path28.join(kbRoot, "escalations.json");
14649
- verdictsFile = (kbRoot) => path28.join(kbRoot, "verdicts.jsonl");
14737
+ escalationsFile = (kbRoot) => path29.join(kbRoot, "escalations.json");
14738
+ verdictsFile = (kbRoot) => path29.join(kbRoot, "verdicts.jsonl");
14650
14739
  needsYouCount = (kbRoot) => readEscalations(kbRoot).filter((e) => e.needsYou).length;
14651
14740
  git = (root, args) => execFileSync8("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
14652
14741
  realGit = {
@@ -14667,13 +14756,13 @@ var init_review = __esm({
14667
14756
  },
14668
14757
  docDate(file) {
14669
14758
  try {
14670
- const d = git(path28.dirname(file), ["log", "-1", "--format=%cI", "--", path28.basename(file)]);
14759
+ const d = git(path29.dirname(file), ["log", "-1", "--format=%cI", "--", path29.basename(file)]);
14671
14760
  if (d)
14672
14761
  return d;
14673
14762
  } catch {
14674
14763
  }
14675
14764
  try {
14676
- return fs27.statSync(file).mtime.toISOString();
14765
+ return fs28.statSync(file).mtime.toISOString();
14677
14766
  } catch {
14678
14767
  return null;
14679
14768
  }
@@ -14682,7 +14771,7 @@ var init_review = __esm({
14682
14771
  nowOf = (c) => c.now?.() ?? /* @__PURE__ */ new Date();
14683
14772
  fileText = (fm, body) => matter5.stringify(body.trim() + "\n", JSON.parse(JSON.stringify(fm)));
14684
14773
  readFm = (file) => {
14685
- const m = matter5(fs27.readFileSync(file, "utf8"));
14774
+ const m = matter5(fs28.readFileSync(file, "utf8"));
14686
14775
  return { fm: m.data, body: m.content };
14687
14776
  };
14688
14777
  ev = (c, event, itemId, extra = {}) => ({ kb: c.kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
@@ -14692,8 +14781,8 @@ var init_review = __esm({
14692
14781
 
14693
14782
  // packages/core/dist/knowledge/fullpass.js
14694
14783
  import crypto5 from "crypto";
14695
- import fs28 from "fs";
14696
- import path29 from "path";
14784
+ import fs29 from "fs";
14785
+ import path30 from "path";
14697
14786
  import matter6 from "gray-matter";
14698
14787
  function dedupPairs(rules) {
14699
14788
  const active = rules.filter((r) => r.status === "active").sort((x, y) => x.id.localeCompare(y.id));
@@ -14710,12 +14799,12 @@ function dedupPairs(rules) {
14710
14799
  return out.slice(0, MAX_DEDUP_PAIRS);
14711
14800
  }
14712
14801
  function readAuditRecords(kb, since, dir = defaultAuditDir()) {
14713
- if (!fs28.existsSync(dir))
14802
+ if (!fs29.existsSync(dir))
14714
14803
  return [];
14715
14804
  const sinceMonth = since.toISOString().slice(0, 7);
14716
14805
  const out = [];
14717
- for (const f of fs28.readdirSync(dir).filter((n) => n.endsWith(".jsonl") && n.slice(0, 7) >= sinceMonth).sort()) {
14718
- for (const line2 of fs28.readFileSync(path29.join(dir, f), "utf8").split("\n")) {
14806
+ for (const f of fs29.readdirSync(dir).filter((n) => n.endsWith(".jsonl") && n.slice(0, 7) >= sinceMonth).sort()) {
14807
+ for (const line2 of fs29.readFileSync(path30.join(dir, f), "utf8").split("\n")) {
14719
14808
  if (!line2.trim())
14720
14809
  continue;
14721
14810
  try {
@@ -14737,7 +14826,7 @@ function usageReview(rules, events) {
14737
14826
  continue;
14738
14827
  if (e.event === "item.surfaced")
14739
14828
  surfaced[e.itemId] = (surfaced[e.itemId] ?? 0) + 1;
14740
- if (e.event === "item.outcome") {
14829
+ if (e.event === "item.outcome" && RATED_SOURCES.has(outcomeSource(e))) {
14741
14830
  if (e.outcome === "noise")
14742
14831
  noise[e.itemId] = (noise[e.itemId] ?? 0) + 1;
14743
14832
  if (e.outcome === "violated")
@@ -14778,8 +14867,8 @@ function checkOverrides(cfg, kb) {
14778
14867
  continue;
14779
14868
  const h = baseHash(b);
14780
14869
  if (!o.overridesBase) {
14781
- const m = matter6(fs28.readFileSync(o.file, "utf8"));
14782
- fs28.writeFileSync(o.file, matter6.stringify(m.content, { ...m.data, overridesBase: h }));
14870
+ const m = matter6(fs29.readFileSync(o.file, "utf8"));
14871
+ fs29.writeFileSync(o.file, matter6.stringify(m.content, { ...m.data, overridesBase: h }));
14783
14872
  continue;
14784
14873
  }
14785
14874
  out.push({ project, ruleId: o.id, file: o.file, baseHash: h, changed: o.overridesBase !== h });
@@ -14822,8 +14911,8 @@ var init_fullpass = __esm({
14822
14911
  });
14823
14912
 
14824
14913
  // packages/core/dist/knowledge/scores.js
14825
- import fs29 from "fs";
14826
- import path30 from "path";
14914
+ import fs30 from "fs";
14915
+ import path31 from "path";
14827
14916
  function tally(records, into = emptyTally()) {
14828
14917
  for (const e of records) {
14829
14918
  const domain = typeof e.domain === "string" && e.domain ? e.domain : "rules";
@@ -14859,17 +14948,25 @@ function tally(records, into = emptyTally()) {
14859
14948
  c.cited++;
14860
14949
  c.lastUsed = later(c.lastUsed, e.ts);
14861
14950
  break;
14862
- case "item.outcome":
14863
- if (OUTCOMES.has(String(e.outcome)))
14864
- c[e.outcome]++;
14951
+ case "item.outcome": {
14952
+ if (!OUTCOMES.has(String(e.outcome)))
14953
+ break;
14954
+ const src = outcomeSource(e), o = e.outcome;
14955
+ const bySrc = into.sources[src] ??= {};
14956
+ bySrc[o] = (bySrc[o] ?? 0) + 1;
14957
+ if (src === "reconcile" && o === "violated")
14958
+ c.codeViolations++;
14959
+ else if (RATED_SOURCES.has(src))
14960
+ c[o]++;
14865
14961
  break;
14962
+ }
14866
14963
  }
14867
14964
  }
14868
14965
  return into;
14869
14966
  }
14870
14967
  function parseLines(file) {
14871
14968
  const out = [];
14872
- for (const line2 of fs29.readFileSync(file, "utf8").split("\n")) {
14969
+ for (const line2 of fs30.readFileSync(file, "utf8").split("\n")) {
14873
14970
  if (!line2.trim())
14874
14971
  continue;
14875
14972
  try {
@@ -14881,37 +14978,37 @@ function parseLines(file) {
14881
14978
  }
14882
14979
  function compactAudit(o) {
14883
14980
  const dir = o.dir ?? defaultAuditDir();
14884
- if (!fs29.existsSync(dir))
14981
+ if (!fs30.existsSync(dir))
14885
14982
  return [];
14886
14983
  const cutoffMonth = new Date(o.now.getTime() - SCORE_WINDOW_DAYS * DAY_MS3).toISOString().slice(0, 7);
14887
14984
  const done = [];
14888
- for (const f of fs29.readdirSync(dir).sort()) {
14985
+ for (const f of fs30.readdirSync(dir).sort()) {
14889
14986
  const m = MONTH_FILE_RE.exec(f);
14890
14987
  if (!m || m[1] >= cutoffMonth)
14891
14988
  continue;
14892
14989
  const [, month, machine] = m;
14893
14990
  const byKb = /* @__PURE__ */ new Map();
14894
- for (const r of parseLines(path30.join(dir, f)))
14991
+ for (const r of parseLines(path31.join(dir, f)))
14895
14992
  byKb.set(r.kb ?? "", [...byKb.get(r.kb ?? "") ?? [], r]);
14896
- const statsPath = path30.join(dir, statsFileName(month, machine));
14897
- const prior = fs29.existsSync(statsPath) ? JSON.parse(fs29.readFileSync(statsPath, "utf8")) : null;
14993
+ const statsPath = path31.join(dir, statsFileName(month, machine));
14994
+ const prior = fs30.existsSync(statsPath) ? JSON.parse(fs30.readFileSync(statsPath, "utf8")) : null;
14898
14995
  const kbs = prior?.kbs ?? {};
14899
14996
  for (const [kb, recs] of byKb)
14900
14997
  kbs[kb] = tally(recs, kbs[kb]);
14901
- fs29.writeFileSync(`${statsPath}.tmp`, JSON.stringify({ month, machine, kbs }));
14902
- fs29.renameSync(`${statsPath}.tmp`, statsPath);
14903
- fs29.unlinkSync(path30.join(dir, f));
14998
+ fs30.writeFileSync(`${statsPath}.tmp`, JSON.stringify({ month, machine, kbs }));
14999
+ fs30.renameSync(`${statsPath}.tmp`, statsPath);
15000
+ fs30.unlinkSync(path31.join(dir, f));
14904
15001
  done.push(month);
14905
15002
  }
14906
15003
  return done;
14907
15004
  }
14908
15005
  function readCompacted(kb, dir) {
14909
15006
  const t = emptyTally();
14910
- if (!fs29.existsSync(dir))
15007
+ if (!fs30.existsSync(dir))
14911
15008
  return t;
14912
- for (const f of fs29.readdirSync(dir).filter((n) => n.endsWith(".stats.json"))) {
15009
+ for (const f of fs30.readdirSync(dir).filter((n) => n.endsWith(".stats.json"))) {
14913
15010
  try {
14914
- const k = JSON.parse(fs29.readFileSync(path30.join(dir, f), "utf8")).kbs[kb];
15011
+ const k = JSON.parse(fs30.readFileSync(path31.join(dir, f), "utf8")).kbs[kb];
14915
15012
  if (k)
14916
15013
  mergeTally(t, k);
14917
15014
  } catch {
@@ -14937,6 +15034,12 @@ function mergeTally(into, from) {
14937
15034
  into.agents[k] = (into.agents[k] ?? 0) + v2;
14938
15035
  for (const [k, v2] of Object.entries(from.tiers))
14939
15036
  into.tiers[k] = (into.tiers[k] ?? 0) + v2;
15037
+ into.sources ??= {};
15038
+ for (const [src, os18] of Object.entries(from.sources ?? {})) {
15039
+ const t = into.sources[src] ??= {};
15040
+ for (const [o, n] of Object.entries(os18))
15041
+ t[o] = (t[o] ?? 0) + n;
15042
+ }
14940
15043
  }
14941
15044
  function computeScores(i) {
14942
15045
  const since = i.now.getTime() - SCORE_WINDOW_DAYS * DAY_MS3;
@@ -14960,11 +15063,14 @@ function computeScores(i) {
14960
15063
  violated: w.violated,
14961
15064
  noise: w.noise,
14962
15065
  wrong: w.wrong,
15066
+ codeViolations: w.codeViolations,
15067
+ evaluated: w.followed + w.violated,
14963
15068
  fireRate: w.surfaced,
14964
15069
  pullRate: w.shown + w.searched,
14965
15070
  useRate: ratio(w.cited, w.surfaced),
14966
15071
  noiseRate: ratio(w.noise, w.surfaced),
14967
15072
  violationRate: ratio(w.violated, w.surfaced),
15073
+ complianceRate: w.followed + w.violated >= COMPLIANCE_MIN_EVALUATED ? ratio(w.followed, w.followed + w.violated) : null,
14968
15074
  lastSurfaced: l?.lastSurfaced,
14969
15075
  lastUsed: l?.lastUsed,
14970
15076
  neverFired30d: w.surfaced === 0 && (knownActive.has(key) || (l?.surfaced ?? 0) > 0),
@@ -14997,53 +15103,58 @@ function computeScores(i) {
14997
15103
  domains,
14998
15104
  perAgentCoverage: win.agents,
14999
15105
  tierContribution: win.tiers,
15000
- reviewerAgreement: { resolved: operator.length, approved, rate: ratio(approved, operator.length) }
15106
+ reviewerAgreement: { resolved: operator.length, approved, rate: ratio(approved, operator.length) },
15107
+ bySource: win.sources
15001
15108
  };
15002
15109
  }
15003
15110
  function scoreKb(o) {
15004
15111
  const dir = o.auditDir ?? defaultAuditDir();
15005
15112
  const records = [];
15006
- if (fs29.existsSync(dir)) {
15007
- for (const f of fs29.readdirSync(dir).filter((n) => MONTH_FILE_RE.test(n)).sort()) {
15008
- records.push(...parseLines(path30.join(dir, f)).filter((r) => r.kb === o.kb));
15113
+ if (fs30.existsSync(dir)) {
15114
+ for (const f of fs30.readdirSync(dir).filter((n) => MONTH_FILE_RE.test(n)).sort()) {
15115
+ records.push(...parseLines(path31.join(dir, f)).filter((r) => r.kb === o.kb));
15009
15116
  }
15010
15117
  }
15011
15118
  let verdicts = [];
15012
15119
  try {
15013
- verdicts = fs29.readFileSync(path30.join(o.kbRoot, "verdicts.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
15120
+ verdicts = fs30.readFileSync(path31.join(o.kbRoot, "verdicts.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
15014
15121
  } catch {
15015
15122
  }
15016
15123
  return computeScores({ kb: o.kb, records, now: o.now, known: o.known, compacted: readCompacted(o.kb, dir), verdicts });
15017
15124
  }
15018
15125
  function writeScores(kbRoot, s) {
15019
- fs29.mkdirSync(kbRoot, { recursive: true });
15020
- fs29.writeFileSync(scoresFile(kbRoot), JSON.stringify(s, null, 2) + "\n");
15126
+ fs30.mkdirSync(kbRoot, { recursive: true });
15127
+ fs30.writeFileSync(scoresFile(kbRoot), JSON.stringify(s, null, 2) + "\n");
15021
15128
  }
15022
15129
  function renderScoresSection(s) {
15023
15130
  const pct = (x) => x === null ? "n/a" : `${Math.round(x * 100)}%`;
15024
15131
  const used = s.items.filter((x) => x.surfaced).sort((a, b) => b.surfaced - a.surfaced || a.itemId.localeCompare(b.itemId)).slice(0, 10);
15025
15132
  const never = s.items.filter((x) => x.neverFired30d).map((x) => x.itemId);
15133
+ const code = s.items.filter((x) => x.codeViolations).map((x) => `${x.itemId} ${x.codeViolations}`);
15134
+ const sources = Object.keys(s.bySource).sort().map((src) => `${src} ${Object.entries(s.bySource[src]).map(([o, n]) => `${o} ${n}`).join(", ")}`);
15026
15135
  return [
15027
15136
  "",
15028
15137
  `## Scores (${s.windowDays} days)`,
15029
15138
  "",
15030
15139
  ...used.length ? [
15031
- "| Item | Surfaced | Pulled | Cited | Use | Noise | Violated |",
15032
- "|---|---|---|---|---|---|---|",
15033
- ...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.pullRate} | ${x.cited} | ${pct(x.useRate)} | ${pct(x.noiseRate)} | ${pct(x.violationRate)} |`)
15140
+ "| Item | Surfaced | Pulled | Cited | Use | Noise | Violated | Compliance |",
15141
+ "|---|---|---|---|---|---|---|---|",
15142
+ ...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.pullRate} | ${x.cited} | ${pct(x.useRate)} | ${pct(x.noiseRate)} | ${pct(x.violationRate)} | ${pct(x.complianceRate)} |`)
15034
15143
  ] : ["No items surfaced."],
15035
15144
  "",
15036
15145
  `- Never fired (${never.length}): ${never.slice(0, 20).join(", ") || "none"}${never.length > 20 ? ", \u2026" : ""}`,
15037
15146
  `- Tier contribution: ${Object.entries(s.tierContribution).map(([k, v2]) => `${k} ${v2}`).join(", ") || "none"}`,
15038
15147
  `- Per-agent coverage (surfaced): ${Object.entries(s.perAgentCoverage).map(([k, v2]) => `${k} ${v2}`).join(", ") || "none"}`,
15039
15148
  `- Reviewer agreement: ${pct(s.reviewerAgreement.rate)} (${s.reviewerAgreement.approved}/${s.reviewerAgreement.resolved} operator resolutions approved)`,
15149
+ `- Outcomes by source: ${sources.join("; ") || "none"} (crew and reconcile are not in the rates)`,
15150
+ `- Code violations (reconcile, not in rates): ${code.join(", ") || "none"}`,
15040
15151
  "",
15041
15152
  "| Domain | Writes/mo | Reads/mo | Chars per citation | Alarm |",
15042
15153
  "|---|---|---|---|---|",
15043
15154
  ...s.domains.map((d) => `| ${d.domain} | ${d.writesPerMonth} | ${d.readsPerMonth} | ${d.charsPerCitation ?? "n/a"} | ${d.deadDomain ? "DEAD (no activity 30d)" : ""} |`)
15044
15155
  ];
15045
15156
  }
15046
- var DAY_MS3, SCORE_WINDOW_DAYS, WRITE_EVENTS, READ_EVENTS, OUTCOMES, zero, later, emptyTally, MONTH_FILE_RE, statsFileName, ratio, scoresFile;
15157
+ var DAY_MS3, SCORE_WINDOW_DAYS, WRITE_EVENTS, READ_EVENTS, OUTCOMES, zero, later, emptyTally, MONTH_FILE_RE, statsFileName, ratio, COMPLIANCE_MIN_EVALUATED, scoresFile;
15047
15158
  var init_scores = __esm({
15048
15159
  "packages/core/dist/knowledge/scores.js"() {
15049
15160
  init_audit();
@@ -15052,19 +15163,20 @@ var init_scores = __esm({
15052
15163
  WRITE_EVENTS = /* @__PURE__ */ new Set(["item.proposed", "item.approved", "item.rejected", "item.applied", "item.promoted", "item.superseded", "item.archived"]);
15053
15164
  READ_EVENTS = /* @__PURE__ */ new Set(["item.surfaced", "item.shown", "item.searched"]);
15054
15165
  OUTCOMES = /* @__PURE__ */ new Set(["followed", "violated", "noise", "wrong"]);
15055
- zero = () => ({ surfaced: 0, suppressed: 0, searched: 0, shown: 0, cited: 0, followed: 0, violated: 0, noise: 0, wrong: 0, chars: 0 });
15166
+ zero = () => ({ surfaced: 0, suppressed: 0, searched: 0, shown: 0, cited: 0, followed: 0, violated: 0, noise: 0, wrong: 0, codeViolations: 0, chars: 0 });
15056
15167
  later = (a, b) => a && b ? a > b ? a : b : a ?? b;
15057
- emptyTally = () => ({ items: {}, domains: {}, agents: {}, tiers: {} });
15168
+ emptyTally = () => ({ items: {}, domains: {}, agents: {}, tiers: {}, sources: {} });
15058
15169
  MONTH_FILE_RE = /^(\d{4}-\d{2})\.(.+)\.jsonl$/;
15059
15170
  statsFileName = (month, machine) => `${month}.${machine}.stats.json`;
15060
15171
  ratio = (n, d) => d ? Math.round(n / d * 1e3) / 1e3 : null;
15061
- scoresFile = (kbRoot) => path30.join(kbRoot, "scores.json");
15172
+ COMPLIANCE_MIN_EVALUATED = 3;
15173
+ scoresFile = (kbRoot) => path31.join(kbRoot, "scores.json");
15062
15174
  }
15063
15175
  });
15064
15176
 
15065
15177
  // packages/core/dist/knowledge/report.js
15066
- import fs30 from "fs";
15067
- import path31 from "path";
15178
+ import fs31 from "fs";
15179
+ import path32 from "path";
15068
15180
  function renderReport(cfg, kb, o) {
15069
15181
  const { rules } = loadKbRules(cfg, kb, { includeProposed: true });
15070
15182
  const count = (s) => rules.filter((r) => r.status === s).length;
@@ -15093,15 +15205,15 @@ function renderReport(cfg, kb, o) {
15093
15205
  }
15094
15206
  if (o.full) {
15095
15207
  const { usage: usage2, caps } = o.full;
15096
- L.push("", "## Usage (30 days)", "", `- Surfaced: ${Object.values(usage2.surfaced).reduce((a, b) => a + b, 0)} times across ${Object.keys(usage2.surfaced).length} rules.`, `- Never surfaced (re-check triggers): ${usage2.neverSurfaced.join(", ") || "none"}`, `- Noisy (narrow triggers): ${usage2.noisy.join(", ") || "none"}`, `- Violation feedback (reword): ${usage2.violated.join(", ") || "none"}`, `- Domains over cap: ${caps.map((c) => `${c.domain} (${c.count}/${c.cap})`).join(", ") || "none"}`);
15208
+ L.push("", "## Usage (30 days)", "", `- Surfaced: ${Object.values(usage2.surfaced).reduce((a, b) => a + b, 0)} times across ${Object.keys(usage2.surfaced).length} rules.`, `- Never surfaced (re-check triggers): ${usage2.neverSurfaced.join(", ") || "none"}`, `- Noisy (narrow triggers): ${usage2.noisy.join(", ") || "none"}`, `- Violated in graded feedback (reword): ${usage2.violated.join(", ") || "none"}`, `- Domains over cap: ${caps.map((c) => `${c.domain} (${c.count}/${c.cap})`).join(", ") || "none"}`);
15097
15209
  }
15098
15210
  if (o.scores)
15099
15211
  L.push(...renderScoresSection(o.scores));
15100
15212
  return L.join("\n") + "\n";
15101
15213
  }
15102
15214
  function writeReport(cfg, kb, o) {
15103
- const file = path31.join(kbDir(cfg, kb), "REPORT.md");
15104
- fs30.writeFileSync(file, renderReport(cfg, kb, o));
15215
+ const file = path32.join(kbDir(cfg, kb), "REPORT.md");
15216
+ fs31.writeFileSync(file, renderReport(cfg, kb, o));
15105
15217
  return file;
15106
15218
  }
15107
15219
  var init_report = __esm({
@@ -15261,6 +15373,7 @@ __export(dist_exports, {
15261
15373
  CITE_LOOKBACK_DAYS: () => CITE_LOOKBACK_DAYS,
15262
15374
  CITE_NOTE: () => CITE_NOTE,
15263
15375
  CMUX_PRESERVE_CLAUDE_AUTH_ENV: () => CMUX_PRESERVE_CLAUDE_AUTH_ENV,
15376
+ COMPLIANCE_MIN_EVALUATED: () => COMPLIANCE_MIN_EVALUATED,
15264
15377
  CONFLICT_409_SELF_HEAL_MS: () => CONFLICT_409_SELF_HEAL_MS,
15265
15378
  CONVERTED_DIR: () => CONVERTED_DIR,
15266
15379
  CREW_GONE_MS: () => CREW_GONE_MS,
@@ -15274,6 +15387,7 @@ __export(dist_exports, {
15274
15387
  DEFAULT_MAX_SECTIONS_PER_PASS: () => DEFAULT_MAX_SECTIONS_PER_PASS,
15275
15388
  DEFAULT_SEARCH_STATUSES: () => DEFAULT_SEARCH_STATUSES,
15276
15389
  DEFAULT_TASK_TIMEOUT_MS: () => DEFAULT_TASK_TIMEOUT_MS,
15390
+ DELIVERY_EVENTS: () => DELIVERY_EVENTS,
15277
15391
  DOCLING_DROP_THRESHOLD: () => DOCLING_DROP_THRESHOLD,
15278
15392
  DeferDelivery: () => DeferDelivery,
15279
15393
  FIRST_TURN_INLINE_MAX_BYTES: () => FIRST_TURN_INLINE_MAX_BYTES,
@@ -15293,6 +15407,7 @@ __export(dist_exports, {
15293
15407
  NOISY_MIN_SURFACED: () => NOISY_MIN_SURFACED,
15294
15408
  NOISY_RATE: () => NOISY_RATE,
15295
15409
  OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
15410
+ OUTCOME_SOURCES: () => OUTCOME_SOURCES,
15296
15411
  PANE_IDLE_AFTER_MS: () => PANE_IDLE_AFTER_MS,
15297
15412
  PASS_THROUGH: () => PASS_THROUGH,
15298
15413
  PROBE_QUIET_MS: () => PROBE_QUIET_MS,
@@ -15301,6 +15416,7 @@ __export(dist_exports, {
15301
15416
  PROMPT_SINGLE_TERM_MIN_SCORE: () => PROMPT_SINGLE_TERM_MIN_SCORE,
15302
15417
  PROPOSED_DIR: () => PROPOSED_DIR,
15303
15418
  PROTOCOL_VERSION: () => PROTOCOL_VERSION,
15419
+ RATED_SOURCES: () => RATED_SOURCES,
15304
15420
  READ_ONLY_CREW_SUBCOMMANDS: () => READ_ONLY_CREW_SUBCOMMANDS,
15305
15421
  READ_ONLY_TOP_LEVEL_COMMANDS: () => READ_ONLY_TOP_LEVEL_COMMANDS,
15306
15422
  ROUTER_READY_ATTEMPTS: () => ROUTER_READY_ATTEMPTS,
@@ -15510,6 +15626,7 @@ __export(dist_exports, {
15510
15626
  loadSessions: () => loadSessions,
15511
15627
  loadSources: () => loadSources,
15512
15628
  loadState: () => loadState,
15629
+ loadedDaemonLogPath: () => loadedDaemonLogPath,
15513
15630
  mailboxStats: () => mailboxStats,
15514
15631
  makeGate: () => makeGate,
15515
15632
  markPendingWarned: () => markPendingWarned,
@@ -15538,9 +15655,11 @@ __export(dist_exports, {
15538
15655
  notePaneScreen: () => notePaneScreen,
15539
15656
  notifyToggle: () => notifyToggle,
15540
15657
  orphanedErrata: () => orphanedErrata,
15658
+ outcomeSource: () => outcomeSource,
15541
15659
  parseBearer: () => parseBearer,
15542
15660
  parseClassifierVerdict: () => parseClassifierVerdict,
15543
15661
  parseCommand: () => parseCommand,
15662
+ parseLaunchctlStderrPath: () => parseLaunchctlStderrPath,
15544
15663
  parseLiveOpencodeServers: () => parseLiveOpencodeServers,
15545
15664
  parseNotifyPref: () => parseNotifyPref,
15546
15665
  parseProgramArgs: () => parseProgramArgs,
@@ -15799,23 +15918,22 @@ init_dist2();
15799
15918
  init_dist2();
15800
15919
  init_dist2();
15801
15920
  init_dist2();
15802
- import { join as join27, dirname as dirname6, resolve as resolve3 } from "path";
15803
- import { homedir as homedir14 } from "os";
15921
+ import { join as join27, dirname as dirname6, resolve as resolve4 } from "path";
15804
15922
  import { fileURLToPath as fileURLToPath3 } from "url";
15805
- import { readFileSync as readFileSync19, statSync as statSync4, existsSync as existsSync13 } from "fs";
15923
+ import { readFileSync as readFileSync19, statSync as statSync4, existsSync as existsSync14 } from "fs";
15806
15924
 
15807
15925
  // packages/agents/dist/drivers/claude.js
15808
15926
  import { execSync as execSync2 } from "child_process";
15809
15927
 
15810
15928
  // packages/agents/dist/sessions/claude-sessions.js
15811
- import { readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
15929
+ import { readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
15812
15930
  import { join as join18 } from "path";
15813
15931
 
15814
15932
  // packages/agents/dist/claude/registry.js
15815
- import fs31 from "fs";
15933
+ import fs32 from "fs";
15816
15934
  import { join as join17 } from "path";
15817
- import { homedir as homedir7 } from "os";
15818
- var CLAUDE_SESSIONS_DIR = join17(homedir7(), ".claude", "sessions");
15935
+ import { homedir as homedir6 } from "os";
15936
+ var CLAUDE_SESSIONS_DIR = join17(homedir6(), ".claude", "sessions");
15819
15937
  var PID_JSON = /^(\d+)\.json$/;
15820
15938
  function parseRegistryDir(files, readFile7) {
15821
15939
  const out = [];
@@ -15857,11 +15975,11 @@ function toLifecycleSnapshot(entry, taskId, alive, now) {
15857
15975
  function readClaudeStatusBySocketPath(socketPath) {
15858
15976
  let files;
15859
15977
  try {
15860
- files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
15978
+ files = fs32.readdirSync(CLAUDE_SESSIONS_DIR);
15861
15979
  } catch {
15862
15980
  return void 0;
15863
15981
  }
15864
- const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
15982
+ const entries = parseRegistryDir(files, (name) => fs32.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
15865
15983
  const entry = entries.find((e) => e.messagingSocketPath === socketPath);
15866
15984
  if (!entry)
15867
15985
  return void 0;
@@ -15878,44 +15996,43 @@ import { execSync as execSync4 } from "child_process";
15878
15996
  import { execSync as execSync5 } from "child_process";
15879
15997
 
15880
15998
  // packages/agents/dist/sessions/opencode-sessions.js
15881
- import { readdirSync as readdirSync5, readFileSync as readFileSync13 } from "fs";
15999
+ init_dist();
16000
+ import { readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
15882
16001
  import { join as join19 } from "path";
15883
- import { homedir as homedir8 } from "os";
15884
- var SQUADRANT_STATE_DIR = join19(homedir8(), ".config", "squadrant", "state");
15885
16002
 
15886
16003
  // packages/agents/dist/drivers/launch-cmd.js
15887
- import fs32 from "fs";
15888
- import path32 from "path";
16004
+ import fs33 from "fs";
16005
+ import path33 from "path";
15889
16006
 
15890
16007
  // packages/agents/dist/projection/cursor.js
15891
16008
  import { mkdir, readFile, writeFile } from "fs/promises";
15892
- import path33 from "path";
15893
- import os9 from "os";
16009
+ import path34 from "path";
16010
+ import os10 from "os";
15894
16011
 
15895
16012
  // packages/agents/dist/projection/codex.js
15896
16013
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
15897
- import path34 from "path";
15898
- import os10 from "os";
16014
+ import path35 from "path";
16015
+ import os11 from "os";
15899
16016
 
15900
16017
  // packages/agents/dist/projection/gemini.js
15901
16018
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
15902
- import path35 from "path";
15903
- import os11 from "os";
16019
+ import path36 from "path";
16020
+ import os12 from "os";
15904
16021
 
15905
16022
  // packages/agents/dist/projection/opencode.js
15906
16023
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
15907
- import path36 from "path";
15908
- import os12 from "os";
16024
+ import path37 from "path";
16025
+ import os13 from "os";
15909
16026
 
15910
16027
  // packages/agents/dist/projection/opencode-skills.js
15911
- import fs33 from "fs";
15912
- import os13 from "os";
15913
- import path37 from "path";
16028
+ import fs34 from "fs";
16029
+ import os14 from "os";
16030
+ import path38 from "path";
15914
16031
  var OPENCODE_SKILL_MARKER = ".squadrant-managed";
15915
16032
  var MARKER_BODY = "squadrant\n";
15916
16033
  function defaultOpencodeSkillsRoot(env = process.env) {
15917
- const configHome = env.XDG_CONFIG_HOME || path37.join(os13.homedir(), ".config");
15918
- return path37.join(configHome, "opencode", "skills");
16034
+ const configHome = env.XDG_CONFIG_HOME || path38.join(os14.homedir(), ".config");
16035
+ return path38.join(configHome, "opencode", "skills");
15919
16036
  }
15920
16037
  var SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
15921
16038
  function parseSkillName(raw) {
@@ -15930,62 +16047,62 @@ function parseSkillName(raw) {
15930
16047
  }
15931
16048
  function listSourceSkills(sourceSkillsDir) {
15932
16049
  const out = /* @__PURE__ */ new Map();
15933
- if (!fs33.existsSync(sourceSkillsDir))
16050
+ if (!fs34.existsSync(sourceSkillsDir))
15934
16051
  return out;
15935
- for (const entry of fs33.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
16052
+ for (const entry of fs34.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
15936
16053
  if (!entry.isDirectory())
15937
16054
  continue;
15938
- const skillPath = path37.join(sourceSkillsDir, entry.name, "SKILL.md");
15939
- if (!fs33.existsSync(skillPath))
16055
+ const skillPath = path38.join(sourceSkillsDir, entry.name, "SKILL.md");
16056
+ if (!fs34.existsSync(skillPath))
15940
16057
  continue;
15941
- const name = parseSkillName(fs33.readFileSync(skillPath, "utf-8"));
16058
+ const name = parseSkillName(fs34.readFileSync(skillPath, "utf-8"));
15942
16059
  if (name && SAFE_NAME.test(name))
15943
16060
  out.set(name, skillPath);
15944
16061
  }
15945
16062
  return out;
15946
16063
  }
15947
16064
  function hasMarker(dir) {
15948
- return fs33.existsSync(path37.join(dir, OPENCODE_SKILL_MARKER));
16065
+ return fs34.existsSync(path38.join(dir, OPENCODE_SKILL_MARKER));
15949
16066
  }
15950
16067
  function syncOpencodeSkills(opts) {
15951
16068
  const result = { written: [], unchanged: [], removed: [], skipped: [] };
15952
16069
  const wanted = listSourceSkills(opts.sourceSkillsDir);
15953
- if (wanted.size === 0 && !fs33.existsSync(opts.sourceSkillsDir))
16070
+ if (wanted.size === 0 && !fs34.existsSync(opts.sourceSkillsDir))
15954
16071
  return result;
15955
16072
  if (!opts.dryRun)
15956
- fs33.mkdirSync(opts.skillsRoot, { recursive: true });
16073
+ fs34.mkdirSync(opts.skillsRoot, { recursive: true });
15957
16074
  for (const [name, srcPath] of wanted) {
15958
- const targetDir = path37.join(opts.skillsRoot, name);
15959
- const targetSkill = path37.join(targetDir, "SKILL.md");
16075
+ const targetDir = path38.join(opts.skillsRoot, name);
16076
+ const targetSkill = path38.join(targetDir, "SKILL.md");
15960
16077
  const managed = hasMarker(targetDir);
15961
- if (fs33.existsSync(targetSkill) && !managed) {
16078
+ if (fs34.existsSync(targetSkill) && !managed) {
15962
16079
  result.skipped.push({ name, reason: "foreign-collision" });
15963
16080
  continue;
15964
16081
  }
15965
- const current = fs33.existsSync(targetSkill) ? fs33.readFileSync(targetSkill) : null;
15966
- if (current && current.equals(fs33.readFileSync(srcPath))) {
16082
+ const current = fs34.existsSync(targetSkill) ? fs34.readFileSync(targetSkill) : null;
16083
+ if (current && current.equals(fs34.readFileSync(srcPath))) {
15967
16084
  if (!managed && !opts.dryRun) {
15968
- fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
16085
+ fs34.writeFileSync(path38.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
15969
16086
  }
15970
16087
  result.unchanged.push(name);
15971
16088
  continue;
15972
16089
  }
15973
16090
  if (!opts.dryRun) {
15974
- fs33.mkdirSync(targetDir, { recursive: true });
15975
- fs33.copyFileSync(srcPath, targetSkill);
15976
- fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
16091
+ fs34.mkdirSync(targetDir, { recursive: true });
16092
+ fs34.copyFileSync(srcPath, targetSkill);
16093
+ fs34.writeFileSync(path38.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
15977
16094
  }
15978
16095
  result.written.push(name);
15979
16096
  }
15980
- if (fs33.existsSync(opts.skillsRoot)) {
15981
- for (const entry of fs33.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
16097
+ if (fs34.existsSync(opts.skillsRoot)) {
16098
+ for (const entry of fs34.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
15982
16099
  if (!entry.isDirectory() || wanted.has(entry.name))
15983
16100
  continue;
15984
- const dir = path37.join(opts.skillsRoot, entry.name);
16101
+ const dir = path38.join(opts.skillsRoot, entry.name);
15985
16102
  if (!hasMarker(dir))
15986
16103
  continue;
15987
16104
  if (!opts.dryRun)
15988
- fs33.rmSync(dir, { recursive: true, force: true });
16105
+ fs34.rmSync(dir, { recursive: true, force: true });
15989
16106
  result.removed.push(entry.name);
15990
16107
  }
15991
16108
  }
@@ -15993,7 +16110,7 @@ function syncOpencodeSkills(opts) {
15993
16110
  }
15994
16111
  function syncShippedOpencodeSkills(opts) {
15995
16112
  return syncOpencodeSkills({
15996
- sourceSkillsDir: path37.join(opts.pkgRoot, "plugin", "skills"),
16113
+ sourceSkillsDir: path38.join(opts.pkgRoot, "plugin", "skills"),
15997
16114
  skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
15998
16115
  dryRun: opts.dryRun
15999
16116
  });
@@ -16001,8 +16118,8 @@ function syncShippedOpencodeSkills(opts) {
16001
16118
 
16002
16119
  // packages/agents/dist/projection/claude.js
16003
16120
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
16004
- import path38 from "path";
16005
- import os14 from "os";
16121
+ import path39 from "path";
16122
+ import os15 from "os";
16006
16123
 
16007
16124
  // packages/agents/dist/codex/app-server-client.js
16008
16125
  import { EventEmitter } from "events";
@@ -16056,8 +16173,8 @@ var AppServerClient = class extends EventEmitter {
16056
16173
  const info = this.opts.clientInfo ?? { name: "squadrant", version: "0" };
16057
16174
  const id = this.nextId++;
16058
16175
  const env = { jsonrpc: "2.0", id, method: "initialize", params: { clientInfo: info } };
16059
- const res = await new Promise((resolve4, reject) => {
16060
- this.pending.set(id, { resolve: resolve4, reject });
16176
+ const res = await new Promise((resolve5, reject) => {
16177
+ this.pending.set(id, { resolve: resolve5, reject });
16061
16178
  this.proc.stdin.write(JSON.stringify(env) + "\n");
16062
16179
  });
16063
16180
  this.proc.stdin.write(JSON.stringify({ jsonrpc: "2.0", method: "initialized" }) + "\n");
@@ -16090,13 +16207,13 @@ var AppServerClient = class extends EventEmitter {
16090
16207
  const turnId = ack?.turn?.id;
16091
16208
  if (typeof turnId !== "string")
16092
16209
  throw new Error(`turn/start: unexpected ack shape (no turn.id): ${JSON.stringify(ack).slice(0, 200)}`);
16093
- return new Promise((resolve4, reject) => {
16210
+ return new Promise((resolve5, reject) => {
16094
16211
  const onNote = (n) => {
16095
16212
  if (n.params?.turn?.id !== turnId)
16096
16213
  return;
16097
16214
  if (n.method === "turn/completed") {
16098
16215
  cleanup();
16099
- resolve4({ turnId });
16216
+ resolve5({ turnId });
16100
16217
  }
16101
16218
  if (n.method === "turn/failed") {
16102
16219
  cleanup();
@@ -16147,8 +16264,8 @@ var AppServerClient = class extends EventEmitter {
16147
16264
  throw new Error("AppServerClient not started");
16148
16265
  const id = this.nextId++;
16149
16266
  const env = { jsonrpc: "2.0", id, method, params: params ?? {} };
16150
- return new Promise((resolve4, reject) => {
16151
- this.pending.set(id, { resolve: resolve4, reject });
16267
+ return new Promise((resolve5, reject) => {
16268
+ this.pending.set(id, { resolve: resolve5, reject });
16152
16269
  this.proc.stdin.write(JSON.stringify(env) + "\n");
16153
16270
  });
16154
16271
  }
@@ -16276,10 +16393,10 @@ function toSnapshot(ev2) {
16276
16393
 
16277
16394
  // packages/agents/dist/codex/config.js
16278
16395
  import { readFile as readFile6 } from "fs/promises";
16279
- import { homedir as homedir9 } from "os";
16396
+ import { homedir as homedir7 } from "os";
16280
16397
  import { join as join20 } from "path";
16281
16398
  async function resolveCodexModel() {
16282
- const home = process.env["CODEX_HOME"] ?? join20(homedir9(), ".codex");
16399
+ const home = process.env["CODEX_HOME"] ?? join20(homedir7(), ".codex");
16283
16400
  const configPath = join20(home, "config.toml");
16284
16401
  let text;
16285
16402
  try {
@@ -16594,11 +16711,11 @@ function buildCodexDeveloperInstructions(rec) {
16594
16711
  ${directive}` : directive;
16595
16712
  }
16596
16713
  function withTimeout(p, ms, msg) {
16597
- return new Promise((resolve4, reject) => {
16714
+ return new Promise((resolve5, reject) => {
16598
16715
  const t = setTimeout(() => reject(new Error(msg)), ms);
16599
16716
  p.then((v2) => {
16600
16717
  clearTimeout(t);
16601
- resolve4(v2);
16718
+ resolve5(v2);
16602
16719
  }, (e) => {
16603
16720
  clearTimeout(t);
16604
16721
  reject(e);
@@ -16839,7 +16956,7 @@ var OpencodeSseBridge = class {
16839
16956
  // packages/agents/dist/interactive/claude.js
16840
16957
  import { execSync as execSync6 } from "child_process";
16841
16958
  import { readFileSync as readFileSync14 } from "fs";
16842
- import { homedir as homedir10 } from "os";
16959
+ import { homedir as homedir8 } from "os";
16843
16960
  import { join as join21 } from "path";
16844
16961
  var nextHookRequestId = Date.now();
16845
16962
 
@@ -16973,14 +17090,14 @@ function runHeadless(opts) {
16973
17090
  if (err.length > ERR_CAP)
16974
17091
  err = err.slice(err.length - ERR_CAP);
16975
17092
  });
16976
- const result = new Promise((resolve4) => {
17093
+ const result = new Promise((resolve5) => {
16977
17094
  child.once("error", (e) => {
16978
17095
  if (debounceTimer) {
16979
17096
  clearTimeout(debounceTimer);
16980
17097
  debounceTimer = null;
16981
17098
  }
16982
17099
  opts.emit({ type: "task.failed", id: opts.id, error: `spawn error: ${e.message}`, exitCode: void 0 });
16983
- resolve4();
17100
+ resolve5();
16984
17101
  });
16985
17102
  child.on("close", (code) => {
16986
17103
  if (chunksSinceProgress > 0)
@@ -16997,14 +17114,14 @@ function runHeadless(opts) {
16997
17114
  const ref = opts.writeResult ? opts.writeResult(opts.id, res.payload ?? "") : "";
16998
17115
  opts.emit({ type: "task.done", id: opts.id, resultRef: ref, parseWarning: res.parseWarning });
16999
17116
  }
17000
- resolve4();
17117
+ resolve5();
17001
17118
  });
17002
17119
  });
17003
17120
  return { result, kill: () => child.kill("SIGTERM") };
17004
17121
  }
17005
17122
 
17006
17123
  // packages/agents/dist/claude/peer-registry-source.js
17007
- import { readdirSync as readdirSync6, readFileSync as readFileSync15 } from "fs";
17124
+ import { readdirSync as readdirSync7, readFileSync as readFileSync15 } from "fs";
17008
17125
  import { join as join22 } from "path";
17009
17126
  function defaultIsAlive(pid) {
17010
17127
  try {
@@ -17029,7 +17146,7 @@ var ClaudePeerRegistrySource = class {
17029
17146
  pollMs;
17030
17147
  log;
17031
17148
  constructor(o = {}) {
17032
- this.readdir = o.readdir ?? (() => readdirSync6(CLAUDE_SESSIONS_DIR));
17149
+ this.readdir = o.readdir ?? (() => readdirSync7(CLAUDE_SESSIONS_DIR));
17033
17150
  this.readFile = o.readFile ?? ((n) => readFileSync15(join22(CLAUDE_SESSIONS_DIR, n), "utf8"));
17034
17151
  this.isAlive = o.isAlive ?? defaultIsAlive;
17035
17152
  this.now = o.now ?? Date.now;
@@ -17128,12 +17245,12 @@ function writeLine(socketPath, envelope, deps) {
17128
17245
  error: `line exceeds the receiver's 1 MiB buffer cap (${Buffer.byteLength(line2, "utf8")} bytes)`
17129
17246
  });
17130
17247
  }
17131
- return new Promise((resolve4) => {
17248
+ return new Promise((resolve5) => {
17132
17249
  let settled = false;
17133
17250
  const done = (r) => {
17134
17251
  if (!settled) {
17135
17252
  settled = true;
17136
- resolve4(r);
17253
+ resolve5(r);
17137
17254
  }
17138
17255
  };
17139
17256
  const sock = deps.connect(socketPath);
@@ -17255,13 +17372,13 @@ var ClaudeReceiptListener = class {
17255
17372
  * target is a live socket and the subsequent listen fails loudly instead.
17256
17373
  */
17257
17374
  start() {
17258
- return new Promise((resolve4, reject) => {
17375
+ return new Promise((resolve5, reject) => {
17259
17376
  this.deps.unlinkStale?.(this.deps.socketPath);
17260
17377
  this.server = this.deps.createServer((conn) => this.handle(conn));
17261
17378
  this.server.once("error", (e) => reject(e));
17262
17379
  this.server.listen(this.deps.socketPath, () => {
17263
17380
  this.server.unref?.();
17264
- resolve4();
17381
+ resolve5();
17265
17382
  });
17266
17383
  });
17267
17384
  }
@@ -17287,15 +17404,15 @@ var ClaudeReceiptListener = class {
17287
17404
  * is silent by design, so "no receipt" is the common, healthy case.
17288
17405
  */
17289
17406
  waitFor(origMsgId, timeoutMs) {
17290
- return new Promise((resolve4) => {
17407
+ return new Promise((resolve5) => {
17291
17408
  const timer = setTimeout(() => {
17292
17409
  this.waiters.delete(origMsgId);
17293
- resolve4(void 0);
17410
+ resolve5(void 0);
17294
17411
  }, timeoutMs);
17295
17412
  this.waiters.set(origMsgId, (r) => {
17296
17413
  clearTimeout(timer);
17297
17414
  this.waiters.delete(origMsgId);
17298
- resolve4(r);
17415
+ resolve5(r);
17299
17416
  });
17300
17417
  });
17301
17418
  }
@@ -17346,9 +17463,9 @@ var ClaudeReceiptListener = class {
17346
17463
  };
17347
17464
 
17348
17465
  // packages/agents/dist/claude/api-key-approval.js
17349
- import fs34 from "fs";
17350
- import os15 from "os";
17351
- import path39 from "path";
17466
+ import fs35 from "fs";
17467
+ import os16 from "os";
17468
+ import path40 from "path";
17352
17469
 
17353
17470
  // packages/agents/dist/opencode/http-channel.js
17354
17471
  init_dist2();
@@ -17440,10 +17557,10 @@ var OpencodeHttpChannel = class {
17440
17557
  return cached;
17441
17558
  const directory = this.directoryFor?.(taskId);
17442
17559
  const createdAfterMs = this.createdAfterFor?.(taskId);
17443
- for (const path43 of ["/session?", "/api/session?"]) {
17560
+ for (const path44 of ["/session?", "/api/session?"]) {
17444
17561
  let res;
17445
17562
  try {
17446
- res = await this.request(`http://127.0.0.1:${port}${path43}`, { method: "GET" });
17563
+ res = await this.request(`http://127.0.0.1:${port}${path44}`, { method: "GET" });
17447
17564
  } catch {
17448
17565
  return void 0;
17449
17566
  }
@@ -17517,9 +17634,9 @@ function createOpencodeFactAdapter(deps) {
17517
17634
  }
17518
17635
 
17519
17636
  // packages/agents/dist/rules-hooks/install.js
17520
- import fs35 from "fs";
17521
- import os16 from "os";
17522
- import path40 from "path";
17637
+ import fs36 from "fs";
17638
+ import os17 from "os";
17639
+ import path41 from "path";
17523
17640
 
17524
17641
  // packages/workspaces/dist/runtimes/cmux.js
17525
17642
  init_dist();
@@ -17536,7 +17653,7 @@ var CmuxTimeoutError = class extends Error {
17536
17653
  }
17537
17654
  };
17538
17655
  function cmux(args) {
17539
- return new Promise((resolve4, reject) => {
17656
+ return new Promise((resolve5, reject) => {
17540
17657
  execFile3(
17541
17658
  resolveCmuxBin(),
17542
17659
  args,
@@ -17550,19 +17667,19 @@ function cmux(args) {
17550
17667
  reject(err.code === "ETIMEDOUT" ? new CmuxTimeoutError(args.join(" ")) : err);
17551
17668
  return;
17552
17669
  }
17553
- resolve4(stdout.trim());
17670
+ resolve5(stdout.trim());
17554
17671
  }
17555
17672
  );
17556
17673
  });
17557
17674
  }
17558
17675
  function cmuxStdin(args, input) {
17559
- return new Promise((resolve4, reject) => {
17676
+ return new Promise((resolve5, reject) => {
17560
17677
  const child = execFile3(resolveCmuxBin(), args, { encoding: "utf-8", timeout: CMUX_TIMEOUT, env: { ...process.env, CMUX_QUIET: "1" } }, (err, stdout) => {
17561
17678
  if (err) {
17562
17679
  reject(err.code === "ETIMEDOUT" ? new CmuxTimeoutError(args.join(" ")) : err);
17563
17680
  return;
17564
17681
  }
17565
- resolve4(stdout.trim());
17682
+ resolve5(stdout.trim());
17566
17683
  });
17567
17684
  child.stdin.end(input);
17568
17685
  });
@@ -18257,9 +18374,9 @@ var NotifierRegistry = class {
18257
18374
  };
18258
18375
 
18259
18376
  // packages/workspaces/dist/workspaces/obsidian.js
18260
- import fs36 from "fs/promises";
18261
- import { existsSync as existsSync11 } from "fs";
18262
- import path41 from "path";
18377
+ import fs37 from "fs/promises";
18378
+ import { existsSync as existsSync12 } from "fs";
18379
+ import path42 from "path";
18263
18380
 
18264
18381
  // packages/workspaces/dist/workspaces/registry.js
18265
18382
  init_dist();
@@ -18331,12 +18448,12 @@ var CmuxEventsBridge = class {
18331
18448
  continue;
18332
18449
  }
18333
18450
  this.child = child;
18334
- await new Promise((resolve4) => {
18451
+ await new Promise((resolve5) => {
18335
18452
  let settled = false;
18336
18453
  const done = () => {
18337
18454
  if (!settled) {
18338
18455
  settled = true;
18339
- resolve4();
18456
+ resolve5();
18340
18457
  }
18341
18458
  };
18342
18459
  child.stdout?.on("data", (b) => this.onData(b));
@@ -18412,9 +18529,9 @@ var CmuxEventsBridge = class {
18412
18529
  // packages/workspaces/dist/cmux-daemon/daemon-cmux.js
18413
18530
  init_dist2();
18414
18531
  init_dist();
18415
- import { readdirSync as readdirSync7, readFileSync as readFileSync16 } from "fs";
18532
+ import { readdirSync as readdirSync8, readFileSync as readFileSync16 } from "fs";
18416
18533
  import { join as join23 } from "path";
18417
- import { homedir as homedir11 } from "os";
18534
+ import { homedir as homedir9 } from "os";
18418
18535
 
18419
18536
  // packages/workspaces/dist/cmux-daemon/store-fingerprint.js
18420
18537
  init_dist();
@@ -18511,11 +18628,11 @@ function readLivenessSnapshot(files, readFile7, projects, argvRecovery = {}) {
18511
18628
 
18512
18629
  // packages/workspaces/dist/cmux-daemon/daemon-cmux.js
18513
18630
  async function readCmuxLiveness() {
18514
- const dir = process.env.CMUX_AGENT_HOOK_STATE_DIR ?? join23(homedir11(), ".cmuxterm");
18631
+ const dir = process.env.CMUX_AGENT_HOOK_STATE_DIR ?? join23(homedir9(), ".cmuxterm");
18515
18632
  const projects = loadConfig().projects;
18516
18633
  let files;
18517
18634
  try {
18518
- files = readdirSync7(dir).filter((f) => f.endsWith("-hook-sessions.json") && !f.endsWith(".lock"));
18635
+ files = readdirSync8(dir).filter((f) => f.endsWith("-hook-sessions.json") && !f.endsWith(".lock"));
18519
18636
  } catch (e) {
18520
18637
  throw new Error(`liveness: could not read cmux state dir ${dir}: ${e.message}`);
18521
18638
  }
@@ -18583,8 +18700,8 @@ var DaemonCmux = class {
18583
18700
 
18584
18701
  // packages/workspaces/dist/cmux-daemon/cmux-store-source.js
18585
18702
  import { join as join24 } from "path";
18586
- import { homedir as homedir12 } from "os";
18587
- import { watch, readdirSync as readdirSync8, readFileSync as readFileSync17, existsSync as existsSync12 } from "fs";
18703
+ import { homedir as homedir10 } from "os";
18704
+ import { watch, readdirSync as readdirSync9, readFileSync as readFileSync17, existsSync as existsSync13 } from "fs";
18588
18705
  var CmuxStoreSource = class {
18589
18706
  name = "cmux-store";
18590
18707
  stateDir;
@@ -18613,7 +18730,7 @@ var CmuxStoreSource = class {
18613
18730
  active = false;
18614
18731
  lastError = null;
18615
18732
  constructor(opts = {}) {
18616
- this.stateDir = opts.stateDir ?? process.env.CMUX_AGENT_HOOK_STATE_DIR ?? join24(homedir12(), ".cmuxterm");
18733
+ this.stateDir = opts.stateDir ?? process.env.CMUX_AGENT_HOOK_STATE_DIR ?? join24(homedir10(), ".cmuxterm");
18617
18734
  this.debounceMs = opts.debounceMs ?? 50;
18618
18735
  this.lockRetryMs = opts.lockRetryMs ?? 50;
18619
18736
  this.maxLockRetries = opts.maxLockRetries ?? 3;
@@ -18621,7 +18738,7 @@ var CmuxStoreSource = class {
18621
18738
  this.isPidAlive = opts.isPidAlive ?? defaultIsPidAlive2;
18622
18739
  this.listFiles = opts.listFiles ?? defaultListFiles;
18623
18740
  this.readFile = opts.readFile ?? defaultReadFile;
18624
- this.fileExists = opts.fileExists ?? existsSync12;
18741
+ this.fileExists = opts.fileExists ?? existsSync13;
18625
18742
  this.watchDir = opts.watchDir ?? defaultWatchDir;
18626
18743
  this.scheduleTimer = opts.scheduleTimer ?? setTimeout;
18627
18744
  this.cancelTimer = opts.cancelTimer ?? clearTimeout;
@@ -18804,14 +18921,14 @@ function defaultIsPidAlive2(pid) {
18804
18921
  }
18805
18922
  function defaultListFiles(dir) {
18806
18923
  try {
18807
- return readdirSync8(dir).filter((f) => f.endsWith("-hook-sessions.json") && !f.endsWith(".lock"));
18924
+ return readdirSync9(dir).filter((f) => f.endsWith("-hook-sessions.json") && !f.endsWith(".lock"));
18808
18925
  } catch {
18809
18926
  return [];
18810
18927
  }
18811
18928
  }
18812
- function defaultReadFile(path43) {
18929
+ function defaultReadFile(path44) {
18813
18930
  try {
18814
- return readFileSync17(path43, "utf-8");
18931
+ return readFileSync17(path44, "utf-8");
18815
18932
  } catch {
18816
18933
  return void 0;
18817
18934
  }
@@ -18828,8 +18945,8 @@ function defaultWatchDir(dir, cb, onError) {
18828
18945
 
18829
18946
  // packages/workspaces/dist/native-hooks/native-hook-source.js
18830
18947
  import { join as join25 } from "path";
18831
- import { homedir as homedir13 } from "os";
18832
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "fs";
18948
+ import { homedir as homedir11 } from "os";
18949
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "fs";
18833
18950
  var CLAUDE_HOOK_EVENTS = [
18834
18951
  ["SessionStart", "session-start"],
18835
18952
  ["UserPromptSubmit", "prompt-submit"],
@@ -18936,7 +19053,7 @@ function removeForeignGateHandlers(entries) {
18936
19053
  return removed;
18937
19054
  }
18938
19055
  function installClaudeHooks(opts = {}) {
18939
- const settingsPath = opts.settingsPath ?? join25(homedir13(), ".claude", "settings.json");
19056
+ const settingsPath = opts.settingsPath ?? join25(homedir11(), ".claude", "settings.json");
18940
19057
  const cliCmd = opts.cliCmd ?? DEFAULT_CLI_CMD;
18941
19058
  const hookCmd = opts.hookCmd ?? `${cliCmd} hooks`;
18942
19059
  const gateCmd = `${cliCmd} gate`;
@@ -19191,16 +19308,16 @@ function extractDetail(sub, payload) {
19191
19308
  }
19192
19309
  return void 0;
19193
19310
  }
19194
- function defaultReadFile2(path43) {
19311
+ function defaultReadFile2(path44) {
19195
19312
  try {
19196
- return readFileSync18(path43, "utf-8");
19313
+ return readFileSync18(path44, "utf-8");
19197
19314
  } catch {
19198
19315
  return void 0;
19199
19316
  }
19200
19317
  }
19201
- function defaultWriteFile(path43, content) {
19202
- mkdirSync8(path43.replace(/\/[^/]+$/, ""), { recursive: true });
19203
- writeFileSync11(path43, content, "utf-8");
19318
+ function defaultWriteFile(path44, content) {
19319
+ mkdirSync9(path44.replace(/\/[^/]+$/, ""), { recursive: true });
19320
+ writeFileSync12(path44, content, "utf-8");
19204
19321
  }
19205
19322
 
19206
19323
  // packages/workspaces/dist/crew-pane.js
@@ -19285,24 +19402,24 @@ init_dist();
19285
19402
 
19286
19403
  // packages/cli/src/lib/daemon-restart-broadcast.ts
19287
19404
  init_dist();
19288
- import path42 from "path";
19289
- function statePath2(stateRoot) {
19290
- return path42.join(stateRoot, "daemon-restart-state.json");
19405
+ import path43 from "path";
19406
+ function statePath2(stateRoot2) {
19407
+ return path43.join(stateRoot2, "daemon-restart-state.json");
19291
19408
  }
19292
19409
  function computeRestartSignature(version, buildMtimeMs) {
19293
19410
  return `${version}::${buildMtimeMs}`;
19294
19411
  }
19295
- function readPersistedRestartSignature(stateRoot) {
19412
+ function readPersistedRestartSignature(stateRoot2) {
19296
19413
  try {
19297
- const raw = readConfigFileSync(statePath2(stateRoot));
19414
+ const raw = readConfigFileSync(statePath2(stateRoot2));
19298
19415
  const data = JSON.parse(raw);
19299
19416
  return typeof data.signature === "string" ? data.signature : null;
19300
19417
  } catch {
19301
19418
  return null;
19302
19419
  }
19303
19420
  }
19304
- function writePersistedRestartSignature(stateRoot, signature) {
19305
- writeConfigFileSync(statePath2(stateRoot), JSON.stringify({ signature }, null, 2) + "\n");
19421
+ function writePersistedRestartSignature(stateRoot2, signature) {
19422
+ writeConfigFileSync(statePath2(stateRoot2), JSON.stringify({ signature }, null, 2) + "\n");
19306
19423
  }
19307
19424
  function restartNotice(version, isDevRebuild) {
19308
19425
  const suffix = isDevRebuild ? " (dev build)" : "";
@@ -19323,20 +19440,20 @@ async function notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebui
19323
19440
  }
19324
19441
  async function maybeBroadcastDaemonRestart(opts) {
19325
19442
  try {
19326
- const { version, buildMtimeMs, stateRoot, config, driver, appendCaptainMessage: appendCaptainMessage2 } = opts;
19443
+ const { version, buildMtimeMs, stateRoot: stateRoot2, config, driver, appendCaptainMessage: appendCaptainMessage2 } = opts;
19327
19444
  const signature = computeRestartSignature(version, buildMtimeMs);
19328
- const previous = readPersistedRestartSignature(stateRoot);
19445
+ const previous = readPersistedRestartSignature(stateRoot2);
19329
19446
  if (previous === signature) return;
19330
19447
  const isDevRebuild = previous !== null && previous.split("::")[0] === version;
19331
19448
  await notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebuild, appendCaptainMessage2);
19332
- writePersistedRestartSignature(stateRoot, signature);
19449
+ writePersistedRestartSignature(stateRoot2, signature);
19333
19450
  } catch {
19334
19451
  }
19335
19452
  }
19336
19453
 
19337
19454
  // packages/cli/src/lib/captain-channel-factory.ts
19338
19455
  import { createServer as createServer4, connect as netConnect } from "net";
19339
- import fs37 from "fs";
19456
+ import fs38 from "fs";
19340
19457
  import { join as join26 } from "path";
19341
19458
  import { randomUUID as randomUUID5 } from "crypto";
19342
19459
  import chalk2 from "chalk";
@@ -19345,15 +19462,15 @@ var shared;
19345
19462
  var registryEntryPath = () => join26(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
19346
19463
  function unregisterSenderIdentity() {
19347
19464
  try {
19348
- fs37.unlinkSync(registryEntryPath());
19465
+ fs38.unlinkSync(registryEntryPath());
19349
19466
  } catch {
19350
19467
  }
19351
19468
  }
19352
19469
  function registerSenderIdentity(socketPath) {
19353
19470
  try {
19354
19471
  unregisterSenderIdentity();
19355
- fs37.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
19356
- fs37.writeFileSync(
19472
+ fs38.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
19473
+ fs38.writeFileSync(
19357
19474
  registryEntryPath(),
19358
19475
  JSON.stringify({
19359
19476
  pid: process.pid,
@@ -19379,7 +19496,7 @@ async function sharedReceiptListener() {
19379
19496
  // must never be the reason we refuse to start.
19380
19497
  unlinkStale: (p) => {
19381
19498
  try {
19382
- fs37.unlinkSync(p);
19499
+ fs38.unlinkSync(p);
19383
19500
  } catch {
19384
19501
  }
19385
19502
  },
@@ -19404,7 +19521,7 @@ async function buildCaptainChannel() {
19404
19521
  // in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
19405
19522
  // missed and every captain ping reported accepted-unconfirmed.
19406
19523
  statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
19407
- wire: (p, e) => writeLine(p, e, { connect: (path43) => netConnect(path43) }),
19524
+ wire: (p, e) => writeLine(p, e, { connect: (path44) => netConnect(path44) }),
19408
19525
  receipts,
19409
19526
  newMsgId: () => randomUUID5(),
19410
19527
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
@@ -19422,8 +19539,8 @@ async function buildCaptainChannels(opts) {
19422
19539
  agentFor: (project) => resolveCaptainAgent(opts.stateRoot, project, opts.configAgent)
19423
19540
  };
19424
19541
  }
19425
- function resolveCaptainAgent(stateRoot, project, configAgent) {
19426
- return readCaptainAddress(stateRoot, project)?.agent ?? configAgent;
19542
+ function resolveCaptainAgent(stateRoot2, project, configAgent) {
19543
+ return readCaptainAddress(stateRoot2, project)?.agent ?? configAgent;
19427
19544
  }
19428
19545
  async function retryForever(build, opts = {}) {
19429
19546
  const sleep3 = opts.sleep ?? ((ms) => new Promise((r) => {
@@ -19463,7 +19580,7 @@ function readPkgVersion() {
19463
19580
  }
19464
19581
  }
19465
19582
  var PKG_VERSION = readPkgVersion();
19466
- function buildTelegramBridge(cfg, stateRoot, log, deliverInbound, usageFor) {
19583
+ function buildTelegramBridge(cfg, stateRoot2, log, deliverInbound, usageFor) {
19467
19584
  const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
19468
19585
  if (!token) {
19469
19586
  log("telegram: config present but no botToken / TELEGRAM_BOT_TOKEN set \u2014 bridge disabled");
@@ -19477,7 +19594,7 @@ function buildTelegramBridge(cfg, stateRoot, log, deliverInbound, usageFor) {
19477
19594
  const runCommand = createRunCommand(CLI_BIN);
19478
19595
  const sendReply = (threadId, text, replyMarkup) => client.sendMessage(cfg.supergroupId, threadId, text, replyMarkup);
19479
19596
  const lifecycle = createInboundLifecycle({
19480
- stateRoot,
19597
+ stateRoot: stateRoot2,
19481
19598
  cfg: { supergroupId: cfg.supergroupId },
19482
19599
  sendChatAction: (chatId, threadId, action) => client.sendChatAction(chatId, threadId, action),
19483
19600
  sendReply: async (threadId, text) => {
@@ -19498,15 +19615,15 @@ function buildTelegramBridge(cfg, stateRoot, log, deliverInbound, usageFor) {
19498
19615
  // timestamp, so the reader hashes the screen and asks the persisted
19499
19616
  // pending store how long that exact screen has been up. Persisted, so a
19500
19617
  // daemon restart cannot hand a dead captain a fresh 15 minutes.
19501
- noteScreen: (project, hash) => notePaneScreen(stateRoot, project, hash, Date.now())
19618
+ noteScreen: (project, hash) => notePaneScreen(stateRoot2, project, hash, Date.now())
19502
19619
  }
19503
19620
  ),
19504
19621
  log
19505
19622
  });
19506
19623
  return createTelegramBridge({
19507
19624
  cfg,
19508
- stateRoot,
19509
- configRoot: dirname6(stateRoot),
19625
+ stateRoot: stateRoot2,
19626
+ configRoot: CONFIG_DIR,
19510
19627
  client,
19511
19628
  appendCaptainMessage,
19512
19629
  log,
@@ -19522,7 +19639,7 @@ function buildTelegramBridge(cfg, stateRoot, log, deliverInbound, usageFor) {
19522
19639
  // every link on the machine. `undefined` correctly means "don't prune".
19523
19640
  registeredProjects: () => {
19524
19641
  try {
19525
- const parsed = JSON.parse(readFileSync19(join27(dirname6(stateRoot), "config.json"), "utf8"));
19642
+ const parsed = JSON.parse(readFileSync19(DEFAULT_CONFIG_PATH, "utf8"));
19526
19643
  return Object.keys(parsed.projects ?? {});
19527
19644
  } catch {
19528
19645
  return void 0;
@@ -19562,8 +19679,18 @@ function startSquadrantd(opts = {}) {
19562
19679
  `
19563
19680
  );
19564
19681
  }
19682
+ if (isDefaultSocket && !opts.stateRoot) {
19683
+ try {
19684
+ const seed = seedStateFromLegacy();
19685
+ if (seed.seeded) process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} state seeded from legacy ${legacyStateDir()} \u2192 ${stateRoot()}
19686
+ `);
19687
+ } catch (err) {
19688
+ process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} legacy state seed failed: ${err instanceof Error ? err.message : String(err)}
19689
+ `);
19690
+ }
19691
+ }
19565
19692
  const ctx = buildContext(opts);
19566
- const { stateRoot, store, log, spawn: spawn2, writeResult, inFlightHeadlessIds, activeHeadlessKills } = ctx;
19693
+ const { stateRoot: stateRoot2, store, log, spawn: spawn2, writeResult, inFlightHeadlessIds, activeHeadlessKills } = ctx;
19567
19694
  const { broadcast, schedulePromotion, cancelPromotionsFor } = createAttach(ctx);
19568
19695
  ctx.broadcast = broadcast;
19569
19696
  ctx.schedulePromotion = schedulePromotion;
@@ -19639,7 +19766,7 @@ function startSquadrantd(opts = {}) {
19639
19766
  const rec = store.listAll().find((r) => r.id === taskId);
19640
19767
  if (!rec) return false;
19641
19768
  try {
19642
- const cfg2 = JSON.parse(readFileSync19(join27(stateRoot, rec.project, taskId, "opencode.json"), "utf8"));
19769
+ const cfg2 = JSON.parse(readFileSync19(join27(stateRoot2, rec.project, taskId, "opencode.json"), "utf8"));
19643
19770
  return cfg2?.permission?.bash === "ask" && cfg2?.permission?.edit === "ask";
19644
19771
  } catch {
19645
19772
  return false;
@@ -19659,7 +19786,7 @@ function startSquadrantd(opts = {}) {
19659
19786
  (r) => r.mode === "interactive" && !TERMINAL_STATES.has(r.state) && r.cwd === hook.cwd
19660
19787
  );
19661
19788
  },
19662
- cursorFile: join27(stateRoot, "cmux-events.seq"),
19789
+ cursorFile: join27(stateRoot2, "cmux-events.seq"),
19663
19790
  log
19664
19791
  });
19665
19792
  const cmuxStoreSource = new CmuxStoreSource({ log });
@@ -19689,7 +19816,7 @@ function startSquadrantd(opts = {}) {
19689
19816
  const tgCfg = loadConfig().telegram;
19690
19817
  ctx.telegramBridge = opts.telegramBridge ?? (tgCfg && !process.env.VITEST ? buildTelegramBridge(
19691
19818
  tgCfg,
19692
- stateRoot,
19819
+ stateRoot2,
19693
19820
  log,
19694
19821
  (project, text) => Promise.resolve().then(() => (init_dist2(), dist_exports)).then((core2) => core2.deliverToCaptain(project, text, {
19695
19822
  channel: ctx.captainChannel,
@@ -19708,7 +19835,7 @@ function startSquadrantd(opts = {}) {
19708
19835
  ctx.captainChannelMode = () => resolveCaptainChannelMode(loadConfig().defaults);
19709
19836
  if (ctx.captainChannelMode() !== "off") {
19710
19837
  void buildCaptainChannelsWithRetry({
19711
- stateRoot: join27(homedir14(), ".config", "squadrant", "state"),
19838
+ stateRoot: ctx.stateRoot,
19712
19839
  configAgent: loadConfig().defaults.roles?.captain?.agent,
19713
19840
  log
19714
19841
  }).then(({ channels, agentFor }) => {
@@ -19923,10 +20050,10 @@ ${buildCompletionProtocol(rec.id, rec.project)}`;
19923
20050
  void maybeBroadcastDaemonRestart({
19924
20051
  version: PKG_VERSION,
19925
20052
  buildMtimeMs,
19926
- stateRoot,
20053
+ stateRoot: stateRoot2,
19927
20054
  config: restartConfig,
19928
20055
  driver: registry.global(restartConfig),
19929
- appendCaptainMessage: (project, text) => appendCaptainMessage({ stateRoot, project, text, source: "daemon" })
20056
+ appendCaptainMessage: (project, text) => appendCaptainMessage({ stateRoot: stateRoot2, project, text, source: "daemon" })
19930
20057
  });
19931
20058
  } catch (e) {
19932
20059
  log(`daemon-restart broadcast setup failed: ${e.message}`);
@@ -19962,8 +20089,8 @@ function logCrashMarker(kind, err) {
19962
20089
  const message = err instanceof Error ? err.stack ?? err.message : String(err);
19963
20090
  process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} ${kind} pid=${process.pid} error=${message}
19964
20091
  `);
19965
- const stateRoot = join27(homedir14(), ".config", "squadrant", "state");
19966
- writeExitMarker(stateRoot, {
20092
+ const stateRoot2 = stateRoot();
20093
+ writeExitMarker(stateRoot2, {
19967
20094
  ts: (/* @__PURE__ */ new Date()).toISOString(),
19968
20095
  pid: process.pid,
19969
20096
  reason: kind,
@@ -19974,8 +20101,8 @@ function logCrashMarker(kind, err) {
19974
20101
  }, (m) => process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} ${m}
19975
20102
  `));
19976
20103
  }
19977
- function isMonorepoCheckout(scriptPath, dirExists = existsSync13) {
19978
- return dirExists(join27(dirname6(resolve3(scriptPath)), "..", "packages"));
20104
+ function isMonorepoCheckout(scriptPath, dirExists = existsSync14) {
20105
+ return dirExists(join27(dirname6(resolve4(scriptPath)), "..", "packages"));
19979
20106
  }
19980
20107
  function isLinkedWorktree(scriptPath, statFile = (p) => {
19981
20108
  try {
@@ -19984,7 +20111,7 @@ function isLinkedWorktree(scriptPath, statFile = (p) => {
19984
20111
  return void 0;
19985
20112
  }
19986
20113
  }) {
19987
- const dotGit = join27(dirname6(resolve3(scriptPath)), "..", ".git");
20114
+ const dotGit = join27(dirname6(resolve4(scriptPath)), "..", ".git");
19988
20115
  return statFile(dotGit)?.isFile === true;
19989
20116
  }
19990
20117
  if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
@@ -20011,13 +20138,13 @@ if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
20011
20138
  sweepMs: 3e4,
20012
20139
  // #898: KB reconcile scheduler on the 60s tick. Enqueues to the home captain's mailbox; never spawns.
20013
20140
  knowledgeTick: async () => {
20014
- const stateRoot = join27(homedir14(), ".config", "squadrant", "state");
20141
+ const stateRoot2 = stateRoot();
20015
20142
  await tickKnowledgeSchedule({
20016
20143
  cfg: loadConfig(),
20017
- stateRoot,
20144
+ stateRoot: stateRoot2,
20018
20145
  log: (m) => process.stderr.write(`[squadrantd] ${m}
20019
20146
  `),
20020
- enqueue: (project, text) => appendCaptainMessage({ stateRoot, project, text, source: "daemon" })
20147
+ enqueue: (project, text) => appendCaptainMessage({ stateRoot: stateRoot2, project, text, source: "daemon" })
20021
20148
  });
20022
20149
  }
20023
20150
  });