@openacp/cli 2026.403.1 → 2026.403.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -462,22 +462,22 @@ __export(config_registry_exports, {
462
462
  });
463
463
  import * as fs4 from "fs";
464
464
  import * as path4 from "path";
465
- function getFieldDef(path32) {
466
- return CONFIG_REGISTRY.find((f) => f.path === path32);
465
+ function getFieldDef(path33) {
466
+ return CONFIG_REGISTRY.find((f) => f.path === path33);
467
467
  }
468
468
  function getSafeFields() {
469
469
  return CONFIG_REGISTRY.filter((f) => f.scope === "safe");
470
470
  }
471
- function isHotReloadable(path32) {
472
- const def = getFieldDef(path32);
471
+ function isHotReloadable(path33) {
472
+ const def = getFieldDef(path33);
473
473
  return def?.hotReload ?? false;
474
474
  }
475
475
  function resolveOptions(def, config) {
476
476
  if (!def.options) return void 0;
477
477
  return typeof def.options === "function" ? def.options(config) : def.options;
478
478
  }
479
- function getConfigValue(config, path32) {
480
- const parts = path32.split(".");
479
+ function getConfigValue(config, path33) {
480
+ const parts = path33.split(".");
481
481
  let current = config;
482
482
  for (const part of parts) {
483
483
  if (current && typeof current === "object" && part in current) {
@@ -1482,7 +1482,115 @@ var init_agents = __esm({
1482
1482
  }
1483
1483
  });
1484
1484
 
1485
+ // src/core/plugin/settings-manager.ts
1486
+ var settings_manager_exports = {};
1487
+ __export(settings_manager_exports, {
1488
+ SettingsManager: () => SettingsManager
1489
+ });
1490
+ import fs18 from "fs";
1491
+ import path17 from "path";
1492
+ var SettingsManager, SettingsAPIImpl;
1493
+ var init_settings_manager = __esm({
1494
+ "src/core/plugin/settings-manager.ts"() {
1495
+ "use strict";
1496
+ SettingsManager = class {
1497
+ constructor(basePath) {
1498
+ this.basePath = basePath;
1499
+ }
1500
+ getBasePath() {
1501
+ return this.basePath;
1502
+ }
1503
+ createAPI(pluginName) {
1504
+ const settingsPath = this.getSettingsPath(pluginName);
1505
+ return new SettingsAPIImpl(settingsPath);
1506
+ }
1507
+ async loadSettings(pluginName) {
1508
+ const settingsPath = this.getSettingsPath(pluginName);
1509
+ try {
1510
+ const content = fs18.readFileSync(settingsPath, "utf-8");
1511
+ return JSON.parse(content);
1512
+ } catch {
1513
+ return {};
1514
+ }
1515
+ }
1516
+ validateSettings(_pluginName, settings, schema) {
1517
+ if (!schema) return { valid: true };
1518
+ const result = schema.safeParse(settings);
1519
+ if (result.success) return { valid: true };
1520
+ return {
1521
+ valid: false,
1522
+ errors: result.error.errors.map(
1523
+ (e) => `${e.path.join(".")}: ${e.message}`
1524
+ )
1525
+ };
1526
+ }
1527
+ getSettingsPath(pluginName) {
1528
+ return path17.join(this.basePath, pluginName, "settings.json");
1529
+ }
1530
+ async getPluginSettings(pluginName) {
1531
+ return this.loadSettings(pluginName);
1532
+ }
1533
+ async updatePluginSettings(pluginName, updates) {
1534
+ const api = this.createAPI(pluginName);
1535
+ const current = await api.getAll();
1536
+ await api.setAll({ ...current, ...updates });
1537
+ }
1538
+ };
1539
+ SettingsAPIImpl = class {
1540
+ constructor(settingsPath) {
1541
+ this.settingsPath = settingsPath;
1542
+ }
1543
+ cache = null;
1544
+ readFile() {
1545
+ if (this.cache !== null) return this.cache;
1546
+ try {
1547
+ const content = fs18.readFileSync(this.settingsPath, "utf-8");
1548
+ this.cache = JSON.parse(content);
1549
+ return this.cache;
1550
+ } catch {
1551
+ this.cache = {};
1552
+ return this.cache;
1553
+ }
1554
+ }
1555
+ writeFile(data) {
1556
+ const dir = path17.dirname(this.settingsPath);
1557
+ fs18.mkdirSync(dir, { recursive: true });
1558
+ fs18.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2));
1559
+ this.cache = data;
1560
+ }
1561
+ async get(key) {
1562
+ const data = this.readFile();
1563
+ return data[key];
1564
+ }
1565
+ async set(key, value) {
1566
+ const data = this.readFile();
1567
+ data[key] = value;
1568
+ this.writeFile(data);
1569
+ }
1570
+ async getAll() {
1571
+ return { ...this.readFile() };
1572
+ }
1573
+ async setAll(settings) {
1574
+ this.writeFile({ ...settings });
1575
+ }
1576
+ async delete(key) {
1577
+ const data = this.readFile();
1578
+ delete data[key];
1579
+ this.writeFile(data);
1580
+ }
1581
+ async clear() {
1582
+ this.writeFile({});
1583
+ }
1584
+ async has(key) {
1585
+ const data = this.readFile();
1586
+ return key in data;
1587
+ }
1588
+ };
1589
+ }
1590
+ });
1591
+
1485
1592
  // src/core/doctor/checks/telegram.ts
1593
+ import * as path18 from "path";
1486
1594
  var BOT_TOKEN_REGEX, telegramCheck;
1487
1595
  var init_telegram = __esm({
1488
1596
  "src/core/doctor/checks/telegram.ts"() {
@@ -1497,13 +1605,16 @@ var init_telegram = __esm({
1497
1605
  results.push({ status: "fail", message: "Cannot check Telegram \u2014 config not loaded" });
1498
1606
  return results;
1499
1607
  }
1500
- const tgConfig = ctx.config.channels.telegram;
1501
- if (!tgConfig || !tgConfig.enabled) {
1502
- results.push({ status: "pass", message: "Telegram not enabled (skipped)" });
1608
+ const { SettingsManager: SettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
1609
+ const sm = new SettingsManager2(path18.join(ctx.pluginsDir, "data"));
1610
+ const ps = await sm.loadSettings("@openacp/telegram");
1611
+ const legacyCh = ctx.config.channels.telegram;
1612
+ const botToken = ps.botToken ?? legacyCh?.botToken;
1613
+ const chatId = ps.chatId ?? legacyCh?.chatId;
1614
+ if (!botToken && !chatId) {
1615
+ results.push({ status: "pass", message: "Telegram not configured (skipped)" });
1503
1616
  return results;
1504
1617
  }
1505
- const botToken = tgConfig.botToken;
1506
- const chatId = tgConfig.chatId;
1507
1618
  if (!botToken || !BOT_TOKEN_REGEX.test(botToken)) {
1508
1619
  results.push({ status: "fail", message: "Bot token format invalid" });
1509
1620
  return results;
@@ -1579,7 +1690,7 @@ var init_telegram = __esm({
1579
1690
  });
1580
1691
 
1581
1692
  // src/core/doctor/checks/storage.ts
1582
- import * as fs18 from "fs";
1693
+ import * as fs19 from "fs";
1583
1694
  var storageCheck;
1584
1695
  var init_storage = __esm({
1585
1696
  "src/core/doctor/checks/storage.ts"() {
@@ -1589,28 +1700,28 @@ var init_storage = __esm({
1589
1700
  order: 4,
1590
1701
  async run(ctx) {
1591
1702
  const results = [];
1592
- if (!fs18.existsSync(ctx.dataDir)) {
1703
+ if (!fs19.existsSync(ctx.dataDir)) {
1593
1704
  results.push({
1594
1705
  status: "fail",
1595
1706
  message: "Data directory ~/.openacp does not exist",
1596
1707
  fixable: true,
1597
1708
  fixRisk: "safe",
1598
1709
  fix: async () => {
1599
- fs18.mkdirSync(ctx.dataDir, { recursive: true });
1710
+ fs19.mkdirSync(ctx.dataDir, { recursive: true });
1600
1711
  return { success: true, message: "created directory" };
1601
1712
  }
1602
1713
  });
1603
1714
  } else {
1604
1715
  try {
1605
- fs18.accessSync(ctx.dataDir, fs18.constants.W_OK);
1716
+ fs19.accessSync(ctx.dataDir, fs19.constants.W_OK);
1606
1717
  results.push({ status: "pass", message: "Data directory exists and writable" });
1607
1718
  } catch {
1608
1719
  results.push({ status: "fail", message: "Data directory not writable" });
1609
1720
  }
1610
1721
  }
1611
- if (fs18.existsSync(ctx.sessionsPath)) {
1722
+ if (fs19.existsSync(ctx.sessionsPath)) {
1612
1723
  try {
1613
- const content = fs18.readFileSync(ctx.sessionsPath, "utf-8");
1724
+ const content = fs19.readFileSync(ctx.sessionsPath, "utf-8");
1614
1725
  const data = JSON.parse(content);
1615
1726
  if (typeof data === "object" && data !== null && "sessions" in data) {
1616
1727
  results.push({ status: "pass", message: "Sessions file valid" });
@@ -1621,7 +1732,7 @@ var init_storage = __esm({
1621
1732
  fixable: true,
1622
1733
  fixRisk: "risky",
1623
1734
  fix: async () => {
1624
- fs18.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));
1735
+ fs19.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));
1625
1736
  return { success: true, message: "reset sessions file" };
1626
1737
  }
1627
1738
  });
@@ -1633,7 +1744,7 @@ var init_storage = __esm({
1633
1744
  fixable: true,
1634
1745
  fixRisk: "risky",
1635
1746
  fix: async () => {
1636
- fs18.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));
1747
+ fs19.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));
1637
1748
  return { success: true, message: "reset sessions file" };
1638
1749
  }
1639
1750
  });
@@ -1641,20 +1752,20 @@ var init_storage = __esm({
1641
1752
  } else {
1642
1753
  results.push({ status: "pass", message: "Sessions file not present yet (created on first session)" });
1643
1754
  }
1644
- if (!fs18.existsSync(ctx.logsDir)) {
1755
+ if (!fs19.existsSync(ctx.logsDir)) {
1645
1756
  results.push({
1646
1757
  status: "warn",
1647
1758
  message: "Log directory does not exist",
1648
1759
  fixable: true,
1649
1760
  fixRisk: "safe",
1650
1761
  fix: async () => {
1651
- fs18.mkdirSync(ctx.logsDir, { recursive: true });
1762
+ fs19.mkdirSync(ctx.logsDir, { recursive: true });
1652
1763
  return { success: true, message: "created log directory" };
1653
1764
  }
1654
1765
  });
1655
1766
  } else {
1656
1767
  try {
1657
- fs18.accessSync(ctx.logsDir, fs18.constants.W_OK);
1768
+ fs19.accessSync(ctx.logsDir, fs19.constants.W_OK);
1658
1769
  results.push({ status: "pass", message: "Log directory exists and writable" });
1659
1770
  } catch {
1660
1771
  results.push({ status: "fail", message: "Log directory not writable" });
@@ -1667,7 +1778,7 @@ var init_storage = __esm({
1667
1778
  });
1668
1779
 
1669
1780
  // src/core/doctor/checks/workspace.ts
1670
- import * as fs19 from "fs";
1781
+ import * as fs20 from "fs";
1671
1782
  var workspaceCheck;
1672
1783
  var init_workspace = __esm({
1673
1784
  "src/core/doctor/checks/workspace.ts"() {
@@ -1683,20 +1794,20 @@ var init_workspace = __esm({
1683
1794
  return results;
1684
1795
  }
1685
1796
  const baseDir = expandHome3(ctx.config.workspace.baseDir);
1686
- if (!fs19.existsSync(baseDir)) {
1797
+ if (!fs20.existsSync(baseDir)) {
1687
1798
  results.push({
1688
1799
  status: "warn",
1689
1800
  message: `Workspace directory does not exist: ${baseDir}`,
1690
1801
  fixable: true,
1691
1802
  fixRisk: "safe",
1692
1803
  fix: async () => {
1693
- fs19.mkdirSync(baseDir, { recursive: true });
1804
+ fs20.mkdirSync(baseDir, { recursive: true });
1694
1805
  return { success: true, message: "created directory" };
1695
1806
  }
1696
1807
  });
1697
1808
  } else {
1698
1809
  try {
1699
- fs19.accessSync(baseDir, fs19.constants.W_OK);
1810
+ fs20.accessSync(baseDir, fs20.constants.W_OK);
1700
1811
  results.push({ status: "pass", message: `Workspace directory exists: ${baseDir}` });
1701
1812
  } catch {
1702
1813
  results.push({ status: "fail", message: `Workspace directory not writable: ${baseDir}` });
@@ -1709,8 +1820,8 @@ var init_workspace = __esm({
1709
1820
  });
1710
1821
 
1711
1822
  // src/core/doctor/checks/plugins.ts
1712
- import * as fs20 from "fs";
1713
- import * as path17 from "path";
1823
+ import * as fs21 from "fs";
1824
+ import * as path19 from "path";
1714
1825
  var pluginsCheck;
1715
1826
  var init_plugins = __esm({
1716
1827
  "src/core/doctor/checks/plugins.ts"() {
@@ -1720,16 +1831,16 @@ var init_plugins = __esm({
1720
1831
  order: 6,
1721
1832
  async run(ctx) {
1722
1833
  const results = [];
1723
- if (!fs20.existsSync(ctx.pluginsDir)) {
1834
+ if (!fs21.existsSync(ctx.pluginsDir)) {
1724
1835
  results.push({
1725
1836
  status: "warn",
1726
1837
  message: "Plugins directory does not exist",
1727
1838
  fixable: true,
1728
1839
  fixRisk: "safe",
1729
1840
  fix: async () => {
1730
- fs20.mkdirSync(ctx.pluginsDir, { recursive: true });
1731
- fs20.writeFileSync(
1732
- path17.join(ctx.pluginsDir, "package.json"),
1841
+ fs21.mkdirSync(ctx.pluginsDir, { recursive: true });
1842
+ fs21.writeFileSync(
1843
+ path19.join(ctx.pluginsDir, "package.json"),
1733
1844
  JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
1734
1845
  );
1735
1846
  return { success: true, message: "initialized plugins directory" };
@@ -1738,15 +1849,15 @@ var init_plugins = __esm({
1738
1849
  return results;
1739
1850
  }
1740
1851
  results.push({ status: "pass", message: "Plugins directory exists" });
1741
- const pkgPath = path17.join(ctx.pluginsDir, "package.json");
1742
- if (!fs20.existsSync(pkgPath)) {
1852
+ const pkgPath = path19.join(ctx.pluginsDir, "package.json");
1853
+ if (!fs21.existsSync(pkgPath)) {
1743
1854
  results.push({
1744
1855
  status: "warn",
1745
1856
  message: "Plugins package.json missing",
1746
1857
  fixable: true,
1747
1858
  fixRisk: "safe",
1748
1859
  fix: async () => {
1749
- fs20.writeFileSync(
1860
+ fs21.writeFileSync(
1750
1861
  pkgPath,
1751
1862
  JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
1752
1863
  );
@@ -1756,7 +1867,7 @@ var init_plugins = __esm({
1756
1867
  return results;
1757
1868
  }
1758
1869
  try {
1759
- const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf-8"));
1870
+ const pkg = JSON.parse(fs21.readFileSync(pkgPath, "utf-8"));
1760
1871
  const deps = pkg.dependencies || {};
1761
1872
  const count = Object.keys(deps).length;
1762
1873
  results.push({ status: "pass", message: `Plugins package.json valid (${count} plugins)` });
@@ -1767,7 +1878,7 @@ var init_plugins = __esm({
1767
1878
  fixable: true,
1768
1879
  fixRisk: "risky",
1769
1880
  fix: async () => {
1770
- fs20.writeFileSync(
1881
+ fs21.writeFileSync(
1771
1882
  pkgPath,
1772
1883
  JSON.stringify({ name: "openacp-plugins", private: true, dependencies: {} }, null, 2)
1773
1884
  );
@@ -1782,7 +1893,7 @@ var init_plugins = __esm({
1782
1893
  });
1783
1894
 
1784
1895
  // src/core/doctor/checks/daemon.ts
1785
- import * as fs21 from "fs";
1896
+ import * as fs22 from "fs";
1786
1897
  import * as net from "net";
1787
1898
  function isProcessAlive(pid) {
1788
1899
  try {
@@ -1812,8 +1923,8 @@ var init_daemon = __esm({
1812
1923
  order: 7,
1813
1924
  async run(ctx) {
1814
1925
  const results = [];
1815
- if (fs21.existsSync(ctx.pidPath)) {
1816
- const content = fs21.readFileSync(ctx.pidPath, "utf-8").trim();
1926
+ if (fs22.existsSync(ctx.pidPath)) {
1927
+ const content = fs22.readFileSync(ctx.pidPath, "utf-8").trim();
1817
1928
  const pid = parseInt(content, 10);
1818
1929
  if (isNaN(pid)) {
1819
1930
  results.push({
@@ -1822,7 +1933,7 @@ var init_daemon = __esm({
1822
1933
  fixable: true,
1823
1934
  fixRisk: "safe",
1824
1935
  fix: async () => {
1825
- fs21.unlinkSync(ctx.pidPath);
1936
+ fs22.unlinkSync(ctx.pidPath);
1826
1937
  return { success: true, message: "removed invalid PID file" };
1827
1938
  }
1828
1939
  });
@@ -1833,7 +1944,7 @@ var init_daemon = __esm({
1833
1944
  fixable: true,
1834
1945
  fixRisk: "safe",
1835
1946
  fix: async () => {
1836
- fs21.unlinkSync(ctx.pidPath);
1947
+ fs22.unlinkSync(ctx.pidPath);
1837
1948
  return { success: true, message: "removed stale PID file" };
1838
1949
  }
1839
1950
  });
@@ -1841,8 +1952,8 @@ var init_daemon = __esm({
1841
1952
  results.push({ status: "pass", message: `Daemon running (PID ${pid})` });
1842
1953
  }
1843
1954
  }
1844
- if (fs21.existsSync(ctx.portFilePath)) {
1845
- const content = fs21.readFileSync(ctx.portFilePath, "utf-8").trim();
1955
+ if (fs22.existsSync(ctx.portFilePath)) {
1956
+ const content = fs22.readFileSync(ctx.portFilePath, "utf-8").trim();
1846
1957
  const port = parseInt(content, 10);
1847
1958
  if (isNaN(port)) {
1848
1959
  results.push({
@@ -1851,7 +1962,7 @@ var init_daemon = __esm({
1851
1962
  fixable: true,
1852
1963
  fixRisk: "safe",
1853
1964
  fix: async () => {
1854
- fs21.unlinkSync(ctx.portFilePath);
1965
+ fs22.unlinkSync(ctx.portFilePath);
1855
1966
  return { success: true, message: "removed invalid port file" };
1856
1967
  }
1857
1968
  });
@@ -1863,8 +1974,8 @@ var init_daemon = __esm({
1863
1974
  const apiPort = ctx.config.api.port;
1864
1975
  const inUse = await checkPortInUse(apiPort);
1865
1976
  if (inUse) {
1866
- if (fs21.existsSync(ctx.pidPath)) {
1867
- const pid = parseInt(fs21.readFileSync(ctx.pidPath, "utf-8").trim(), 10);
1977
+ if (fs22.existsSync(ctx.pidPath)) {
1978
+ const pid = parseInt(fs22.readFileSync(ctx.pidPath, "utf-8").trim(), 10);
1868
1979
  if (!isNaN(pid) && isProcessAlive(pid)) {
1869
1980
  results.push({ status: "pass", message: `API port ${apiPort} in use by OpenACP daemon` });
1870
1981
  } else {
@@ -1884,17 +1995,17 @@ var init_daemon = __esm({
1884
1995
  });
1885
1996
 
1886
1997
  // src/core/utils/install-binary.ts
1887
- import fs22 from "fs";
1888
- import path18 from "path";
1998
+ import fs23 from "fs";
1999
+ import path20 from "path";
1889
2000
  import https from "https";
1890
2001
  import os9 from "os";
1891
2002
  import { execSync } from "child_process";
1892
2003
  function downloadFile(url, dest) {
1893
2004
  return new Promise((resolve6, reject) => {
1894
- const file = fs22.createWriteStream(dest);
2005
+ const file = fs23.createWriteStream(dest);
1895
2006
  const cleanup = () => {
1896
2007
  try {
1897
- if (fs22.existsSync(dest)) fs22.unlinkSync(dest);
2008
+ if (fs23.existsSync(dest)) fs23.unlinkSync(dest);
1898
2009
  } catch {
1899
2010
  }
1900
2011
  };
@@ -1941,34 +2052,34 @@ function getDownloadUrl(spec) {
1941
2052
  async function ensureBinary(spec, binDir) {
1942
2053
  const resolvedBinDir = binDir ?? DEFAULT_BIN_DIR;
1943
2054
  const binName = IS_WINDOWS ? `${spec.name}.exe` : spec.name;
1944
- const binPath = path18.join(resolvedBinDir, binName);
2055
+ const binPath = path20.join(resolvedBinDir, binName);
1945
2056
  if (commandExists(spec.name)) {
1946
2057
  log17.debug({ name: spec.name }, "Found in PATH");
1947
2058
  return spec.name;
1948
2059
  }
1949
- if (fs22.existsSync(binPath)) {
1950
- if (!IS_WINDOWS) fs22.chmodSync(binPath, "755");
2060
+ if (fs23.existsSync(binPath)) {
2061
+ if (!IS_WINDOWS) fs23.chmodSync(binPath, "755");
1951
2062
  log17.debug({ name: spec.name, path: binPath }, "Found in ~/.openacp/bin");
1952
2063
  return binPath;
1953
2064
  }
1954
2065
  log17.info({ name: spec.name }, "Not found, downloading from GitHub...");
1955
- fs22.mkdirSync(resolvedBinDir, { recursive: true });
2066
+ fs23.mkdirSync(resolvedBinDir, { recursive: true });
1956
2067
  const url = getDownloadUrl(spec);
1957
2068
  const isArchive = spec.isArchive?.(url) ?? false;
1958
- const downloadDest = isArchive ? path18.join(resolvedBinDir, `${spec.name}.tgz`) : binPath;
2069
+ const downloadDest = isArchive ? path20.join(resolvedBinDir, `${spec.name}.tgz`) : binPath;
1959
2070
  await downloadFile(url, downloadDest);
1960
2071
  if (isArchive) {
1961
2072
  execSync(`tar -xzf "${downloadDest}" -C "${resolvedBinDir}"`, { stdio: "pipe" });
1962
2073
  try {
1963
- fs22.unlinkSync(downloadDest);
2074
+ fs23.unlinkSync(downloadDest);
1964
2075
  } catch {
1965
2076
  }
1966
2077
  }
1967
- if (!fs22.existsSync(binPath)) {
2078
+ if (!fs23.existsSync(binPath)) {
1968
2079
  throw new Error(`${spec.name}: binary not found at ${binPath} after download/extraction. The archive structure may have changed.`);
1969
2080
  }
1970
2081
  if (!IS_WINDOWS) {
1971
- fs22.chmodSync(binPath, "755");
2082
+ fs23.chmodSync(binPath, "755");
1972
2083
  }
1973
2084
  log17.info({ name: spec.name, path: binPath }, "Installed successfully");
1974
2085
  return binPath;
@@ -1980,7 +2091,7 @@ var init_install_binary = __esm({
1980
2091
  init_log();
1981
2092
  init_agent_dependencies();
1982
2093
  log17 = createChildLogger({ module: "binary-installer" });
1983
- DEFAULT_BIN_DIR = path18.join(os9.homedir(), ".openacp", "bin");
2094
+ DEFAULT_BIN_DIR = path20.join(os9.homedir(), ".openacp", "bin");
1984
2095
  IS_WINDOWS = os9.platform() === "win32";
1985
2096
  }
1986
2097
  });
@@ -2021,8 +2132,8 @@ var init_install_cloudflared = __esm({
2021
2132
  });
2022
2133
 
2023
2134
  // src/core/doctor/checks/tunnel.ts
2024
- import * as fs23 from "fs";
2025
- import * as path19 from "path";
2135
+ import * as fs24 from "fs";
2136
+ import * as path21 from "path";
2026
2137
  import * as os10 from "os";
2027
2138
  import { execFileSync as execFileSync4 } from "child_process";
2028
2139
  var tunnelCheck;
@@ -2046,9 +2157,9 @@ var init_tunnel = __esm({
2046
2157
  results.push({ status: "pass", message: `Tunnel provider: ${provider}` });
2047
2158
  if (provider === "cloudflare") {
2048
2159
  const binName = os10.platform() === "win32" ? "cloudflared.exe" : "cloudflared";
2049
- const binPath = path19.join(ctx.dataDir, "bin", binName);
2160
+ const binPath = path21.join(ctx.dataDir, "bin", binName);
2050
2161
  let found = false;
2051
- if (fs23.existsSync(binPath)) {
2162
+ if (fs24.existsSync(binPath)) {
2052
2163
  found = true;
2053
2164
  } else {
2054
2165
  try {
@@ -2090,8 +2201,8 @@ var init_tunnel = __esm({
2090
2201
  });
2091
2202
 
2092
2203
  // src/core/doctor/index.ts
2093
- import * as fs24 from "fs";
2094
- import * as path20 from "path";
2204
+ import * as fs25 from "fs";
2205
+ import * as path22 from "path";
2095
2206
  var ALL_CHECKS, CHECK_TIMEOUT_MS, DoctorEngine;
2096
2207
  var init_doctor = __esm({
2097
2208
  "src/core/doctor/index.ts"() {
@@ -2173,27 +2284,27 @@ var init_doctor = __esm({
2173
2284
  }
2174
2285
  async buildContext() {
2175
2286
  const dataDir = this.dataDir;
2176
- const configPath = process.env.OPENACP_CONFIG_PATH || path20.join(dataDir, "config.json");
2287
+ const configPath = process.env.OPENACP_CONFIG_PATH || path22.join(dataDir, "config.json");
2177
2288
  let config = null;
2178
2289
  let rawConfig = null;
2179
2290
  try {
2180
- const content = fs24.readFileSync(configPath, "utf-8");
2291
+ const content = fs25.readFileSync(configPath, "utf-8");
2181
2292
  rawConfig = JSON.parse(content);
2182
2293
  const cm = new ConfigManager(configPath);
2183
2294
  await cm.load();
2184
2295
  config = cm.get();
2185
2296
  } catch {
2186
2297
  }
2187
- const logsDir = config ? expandHome3(config.logging.logDir) : path20.join(dataDir, "logs");
2298
+ const logsDir = config ? expandHome3(config.logging.logDir) : path22.join(dataDir, "logs");
2188
2299
  return {
2189
2300
  config,
2190
2301
  rawConfig,
2191
2302
  configPath,
2192
2303
  dataDir,
2193
- sessionsPath: path20.join(dataDir, "sessions.json"),
2194
- pidPath: path20.join(dataDir, "openacp.pid"),
2195
- portFilePath: path20.join(dataDir, "api.port"),
2196
- pluginsDir: path20.join(dataDir, "plugins"),
2304
+ sessionsPath: path22.join(dataDir, "sessions.json"),
2305
+ pidPath: path22.join(dataDir, "openacp.pid"),
2306
+ portFilePath: path22.join(dataDir, "api.port"),
2307
+ pluginsDir: path22.join(dataDir, "plugins"),
2197
2308
  logsDir
2198
2309
  };
2199
2310
  }
@@ -2298,16 +2409,16 @@ __export(plugin_installer_exports, {
2298
2409
  });
2299
2410
  import { exec } from "child_process";
2300
2411
  import { promisify } from "util";
2301
- import * as fs26 from "fs/promises";
2412
+ import * as fs27 from "fs/promises";
2302
2413
  import * as os12 from "os";
2303
- import * as path22 from "path";
2414
+ import * as path24 from "path";
2304
2415
  import { pathToFileURL } from "url";
2305
2416
  async function importFromDir(packageName, dir) {
2306
- const pkgDir = path22.join(dir, "node_modules", ...packageName.split("/"));
2307
- const pkgJsonPath = path22.join(pkgDir, "package.json");
2417
+ const pkgDir = path24.join(dir, "node_modules", ...packageName.split("/"));
2418
+ const pkgJsonPath = path24.join(pkgDir, "package.json");
2308
2419
  let pkgJson;
2309
2420
  try {
2310
- pkgJson = JSON.parse(await fs26.readFile(pkgJsonPath, "utf-8"));
2421
+ pkgJson = JSON.parse(await fs27.readFile(pkgJsonPath, "utf-8"));
2311
2422
  } catch (err) {
2312
2423
  throw new Error(`Cannot read package.json for "${packageName}" at ${pkgJsonPath}: ${err.message}`);
2313
2424
  }
@@ -2320,9 +2431,9 @@ async function importFromDir(packageName, dir) {
2320
2431
  } else {
2321
2432
  entry = pkgJson.main ?? "index.js";
2322
2433
  }
2323
- const entryPath = path22.join(pkgDir, entry);
2434
+ const entryPath = path24.join(pkgDir, entry);
2324
2435
  try {
2325
- await fs26.access(entryPath);
2436
+ await fs27.access(entryPath);
2326
2437
  } catch {
2327
2438
  throw new Error(`Entry point "${entry}" not found for "${packageName}" at ${entryPath}`);
2328
2439
  }
@@ -2332,7 +2443,7 @@ async function installNpmPlugin(packageName, pluginsDir) {
2332
2443
  if (!VALID_NPM_NAME.test(packageName)) {
2333
2444
  throw new Error(`Invalid package name: "${packageName}". Must be a valid npm package name.`);
2334
2445
  }
2335
- const dir = pluginsDir ?? path22.join(os12.homedir(), ".openacp", "plugins");
2446
+ const dir = pluginsDir ?? path24.join(os12.homedir(), ".openacp", "plugins");
2336
2447
  try {
2337
2448
  return await importFromDir(packageName, dir);
2338
2449
  } catch {
@@ -2351,113 +2462,6 @@ var init_plugin_installer = __esm({
2351
2462
  }
2352
2463
  });
2353
2464
 
2354
- // src/core/plugin/settings-manager.ts
2355
- var settings_manager_exports = {};
2356
- __export(settings_manager_exports, {
2357
- SettingsManager: () => SettingsManager
2358
- });
2359
- import fs27 from "fs";
2360
- import path23 from "path";
2361
- var SettingsManager, SettingsAPIImpl;
2362
- var init_settings_manager = __esm({
2363
- "src/core/plugin/settings-manager.ts"() {
2364
- "use strict";
2365
- SettingsManager = class {
2366
- constructor(basePath) {
2367
- this.basePath = basePath;
2368
- }
2369
- getBasePath() {
2370
- return this.basePath;
2371
- }
2372
- createAPI(pluginName) {
2373
- const settingsPath = this.getSettingsPath(pluginName);
2374
- return new SettingsAPIImpl(settingsPath);
2375
- }
2376
- async loadSettings(pluginName) {
2377
- const settingsPath = this.getSettingsPath(pluginName);
2378
- try {
2379
- const content = fs27.readFileSync(settingsPath, "utf-8");
2380
- return JSON.parse(content);
2381
- } catch {
2382
- return {};
2383
- }
2384
- }
2385
- validateSettings(_pluginName, settings, schema) {
2386
- if (!schema) return { valid: true };
2387
- const result = schema.safeParse(settings);
2388
- if (result.success) return { valid: true };
2389
- return {
2390
- valid: false,
2391
- errors: result.error.errors.map(
2392
- (e) => `${e.path.join(".")}: ${e.message}`
2393
- )
2394
- };
2395
- }
2396
- getSettingsPath(pluginName) {
2397
- return path23.join(this.basePath, pluginName, "settings.json");
2398
- }
2399
- async getPluginSettings(pluginName) {
2400
- return this.loadSettings(pluginName);
2401
- }
2402
- async updatePluginSettings(pluginName, updates) {
2403
- const api = this.createAPI(pluginName);
2404
- const current = await api.getAll();
2405
- await api.setAll({ ...current, ...updates });
2406
- }
2407
- };
2408
- SettingsAPIImpl = class {
2409
- constructor(settingsPath) {
2410
- this.settingsPath = settingsPath;
2411
- }
2412
- cache = null;
2413
- readFile() {
2414
- if (this.cache !== null) return this.cache;
2415
- try {
2416
- const content = fs27.readFileSync(this.settingsPath, "utf-8");
2417
- this.cache = JSON.parse(content);
2418
- return this.cache;
2419
- } catch {
2420
- this.cache = {};
2421
- return this.cache;
2422
- }
2423
- }
2424
- writeFile(data) {
2425
- const dir = path23.dirname(this.settingsPath);
2426
- fs27.mkdirSync(dir, { recursive: true });
2427
- fs27.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2));
2428
- this.cache = data;
2429
- }
2430
- async get(key) {
2431
- const data = this.readFile();
2432
- return data[key];
2433
- }
2434
- async set(key, value) {
2435
- const data = this.readFile();
2436
- data[key] = value;
2437
- this.writeFile(data);
2438
- }
2439
- async getAll() {
2440
- return { ...this.readFile() };
2441
- }
2442
- async setAll(settings) {
2443
- this.writeFile({ ...settings });
2444
- }
2445
- async delete(key) {
2446
- const data = this.readFile();
2447
- delete data[key];
2448
- this.writeFile(data);
2449
- }
2450
- async clear() {
2451
- this.writeFile({});
2452
- }
2453
- async has(key) {
2454
- const data = this.readFile();
2455
- return key in data;
2456
- }
2457
- };
2458
- }
2459
- });
2460
-
2461
2465
  // src/core/plugin/terminal-io.ts
2462
2466
  import * as clack from "@clack/prompts";
2463
2467
  function isCancel(value) {
@@ -2521,10 +2525,10 @@ var install_context_exports = {};
2521
2525
  __export(install_context_exports, {
2522
2526
  createInstallContext: () => createInstallContext
2523
2527
  });
2524
- import path24 from "path";
2528
+ import path25 from "path";
2525
2529
  function createInstallContext(opts) {
2526
2530
  const { pluginName, settingsManager, basePath, legacyConfig, instanceRoot } = opts;
2527
- const dataDir = path24.join(basePath, pluginName, "data");
2531
+ const dataDir = path25.join(basePath, pluginName, "data");
2528
2532
  return {
2529
2533
  pluginName,
2530
2534
  terminal: createTerminalIO(),
@@ -2552,13 +2556,13 @@ __export(api_client_exports, {
2552
2556
  removeStalePortFile: () => removeStalePortFile
2553
2557
  });
2554
2558
  import * as fs28 from "fs";
2555
- import * as path25 from "path";
2559
+ import * as path26 from "path";
2556
2560
  import * as os13 from "os";
2557
2561
  function defaultPortFile(root) {
2558
- return path25.join(root ?? DEFAULT_ROOT, "api.port");
2562
+ return path26.join(root ?? DEFAULT_ROOT, "api.port");
2559
2563
  }
2560
2564
  function defaultSecretFile(root) {
2561
- return path25.join(root ?? DEFAULT_ROOT, "api-secret");
2565
+ return path26.join(root ?? DEFAULT_ROOT, "api-secret");
2562
2566
  }
2563
2567
  function readApiPort(portFilePath, instanceRoot) {
2564
2568
  const filePath = portFilePath ?? defaultPortFile(instanceRoot);
@@ -2598,7 +2602,7 @@ var DEFAULT_ROOT;
2598
2602
  var init_api_client = __esm({
2599
2603
  "src/cli/api-client.ts"() {
2600
2604
  "use strict";
2601
- DEFAULT_ROOT = path25.join(os13.homedir(), ".openacp");
2605
+ DEFAULT_ROOT = path26.join(os13.homedir(), ".openacp");
2602
2606
  }
2603
2607
  });
2604
2608
 
@@ -2633,7 +2637,7 @@ var init_notification = __esm({
2633
2637
 
2634
2638
  // src/plugins/file-service/file-service.ts
2635
2639
  import fs30 from "fs";
2636
- import path28 from "path";
2640
+ import path29 from "path";
2637
2641
  import { OggOpusDecoder } from "ogg-opus-decoder";
2638
2642
  import wav from "node-wav";
2639
2643
  function classifyMime(mimeType) {
@@ -2692,7 +2696,7 @@ var init_file_service = __esm({
2692
2696
  const entries = await fs30.promises.readdir(this.baseDir, { withFileTypes: true });
2693
2697
  for (const entry of entries) {
2694
2698
  if (!entry.isDirectory()) continue;
2695
- const dirPath = path28.join(this.baseDir, entry.name);
2699
+ const dirPath = path29.join(this.baseDir, entry.name);
2696
2700
  try {
2697
2701
  const stat = await fs30.promises.stat(dirPath);
2698
2702
  if (stat.mtimeMs < cutoff) {
@@ -2707,10 +2711,10 @@ var init_file_service = __esm({
2707
2711
  return removed;
2708
2712
  }
2709
2713
  async saveFile(sessionId, fileName, data, mimeType) {
2710
- const sessionDir = path28.join(this.baseDir, sessionId);
2714
+ const sessionDir = path29.join(this.baseDir, sessionId);
2711
2715
  await fs30.promises.mkdir(sessionDir, { recursive: true });
2712
2716
  const safeName = `${Date.now()}-${fileName.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
2713
- const filePath = path28.join(sessionDir, safeName);
2717
+ const filePath = path29.join(sessionDir, safeName);
2714
2718
  await fs30.promises.writeFile(filePath, data);
2715
2719
  return {
2716
2720
  type: classifyMime(mimeType),
@@ -2724,12 +2728,12 @@ var init_file_service = __esm({
2724
2728
  try {
2725
2729
  const stat = await fs30.promises.stat(filePath);
2726
2730
  if (!stat.isFile()) return null;
2727
- const ext = path28.extname(filePath).toLowerCase();
2731
+ const ext = path29.extname(filePath).toLowerCase();
2728
2732
  const mimeType = EXT_TO_MIME[ext] || "application/octet-stream";
2729
2733
  return {
2730
2734
  type: classifyMime(mimeType),
2731
2735
  filePath,
2732
- fileName: path28.basename(filePath),
2736
+ fileName: path29.basename(filePath),
2733
2737
  mimeType,
2734
2738
  size: stat.size
2735
2739
  };
@@ -3253,7 +3257,7 @@ data: ${JSON.stringify(data)}
3253
3257
 
3254
3258
  // src/plugins/api-server/static-server.ts
3255
3259
  import * as fs31 from "fs";
3256
- import * as path29 from "path";
3260
+ import * as path30 from "path";
3257
3261
  import { fileURLToPath } from "url";
3258
3262
  var MIME_TYPES, StaticServer;
3259
3263
  var init_static_server = __esm({
@@ -3277,16 +3281,16 @@ var init_static_server = __esm({
3277
3281
  this.uiDir = uiDir;
3278
3282
  if (!this.uiDir) {
3279
3283
  const __filename = fileURLToPath(import.meta.url);
3280
- const candidate = path29.resolve(path29.dirname(__filename), "../../ui/dist");
3281
- if (fs31.existsSync(path29.join(candidate, "index.html"))) {
3284
+ const candidate = path30.resolve(path30.dirname(__filename), "../../ui/dist");
3285
+ if (fs31.existsSync(path30.join(candidate, "index.html"))) {
3282
3286
  this.uiDir = candidate;
3283
3287
  }
3284
3288
  if (!this.uiDir) {
3285
- const publishCandidate = path29.resolve(
3286
- path29.dirname(__filename),
3289
+ const publishCandidate = path30.resolve(
3290
+ path30.dirname(__filename),
3287
3291
  "../ui"
3288
3292
  );
3289
- if (fs31.existsSync(path29.join(publishCandidate, "index.html"))) {
3293
+ if (fs31.existsSync(path30.join(publishCandidate, "index.html"))) {
3290
3294
  this.uiDir = publishCandidate;
3291
3295
  }
3292
3296
  }
@@ -3298,12 +3302,12 @@ var init_static_server = __esm({
3298
3302
  serve(req, res) {
3299
3303
  if (!this.uiDir) return false;
3300
3304
  const urlPath = (req.url || "/").split("?")[0];
3301
- const safePath = path29.normalize(urlPath);
3302
- const filePath = path29.join(this.uiDir, safePath);
3303
- if (!filePath.startsWith(this.uiDir + path29.sep) && filePath !== this.uiDir)
3305
+ const safePath = path30.normalize(urlPath);
3306
+ const filePath = path30.join(this.uiDir, safePath);
3307
+ if (!filePath.startsWith(this.uiDir + path30.sep) && filePath !== this.uiDir)
3304
3308
  return false;
3305
3309
  if (fs31.existsSync(filePath) && fs31.statSync(filePath).isFile()) {
3306
- const ext = path29.extname(filePath);
3310
+ const ext = path30.extname(filePath);
3307
3311
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
3308
3312
  const isHashed = /\.[a-zA-Z0-9]{8,}\.(js|css)$/.test(filePath);
3309
3313
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "no-cache";
@@ -3314,7 +3318,7 @@ var init_static_server = __esm({
3314
3318
  fs31.createReadStream(filePath).pipe(res);
3315
3319
  return true;
3316
3320
  }
3317
- const indexPath = path29.join(this.uiDir, "index.html");
3321
+ const indexPath = path30.join(this.uiDir, "index.html");
3318
3322
  if (fs31.existsSync(indexPath)) {
3319
3323
  res.writeHead(200, {
3320
3324
  "Content-Type": "text/html; charset=utf-8",
@@ -3476,7 +3480,7 @@ var init_exports = __esm({
3476
3480
 
3477
3481
  // src/plugins/context/context-cache.ts
3478
3482
  import * as fs32 from "fs";
3479
- import * as path30 from "path";
3483
+ import * as path31 from "path";
3480
3484
  import * as crypto from "crypto";
3481
3485
  var DEFAULT_TTL_MS, ContextCache;
3482
3486
  var init_context_cache = __esm({
@@ -3493,7 +3497,7 @@ var init_context_cache = __esm({
3493
3497
  return crypto.createHash("sha256").update(`${repoPath}:${queryKey}`).digest("hex").slice(0, 16);
3494
3498
  }
3495
3499
  filePath(repoPath, queryKey) {
3496
- return path30.join(this.cacheDir, `${this.keyHash(repoPath, queryKey)}.json`);
3500
+ return path31.join(this.cacheDir, `${this.keyHash(repoPath, queryKey)}.json`);
3497
3501
  }
3498
3502
  get(repoPath, queryKey) {
3499
3503
  const fp = this.filePath(repoPath, queryKey);
@@ -3517,7 +3521,7 @@ var init_context_cache = __esm({
3517
3521
 
3518
3522
  // src/plugins/context/context-manager.ts
3519
3523
  import * as os15 from "os";
3520
- import * as path31 from "path";
3524
+ import * as path32 from "path";
3521
3525
  var ContextManager;
3522
3526
  var init_context_manager = __esm({
3523
3527
  "src/plugins/context/context-manager.ts"() {
@@ -3528,7 +3532,7 @@ var init_context_manager = __esm({
3528
3532
  cache;
3529
3533
  historyStore;
3530
3534
  constructor(cachePath) {
3531
- this.cache = new ContextCache(cachePath ?? path31.join(os15.homedir(), ".openacp", "cache", "entire"));
3535
+ this.cache = new ContextCache(cachePath ?? path32.join(os15.homedir(), ".openacp", "cache", "entire"));
3532
3536
  }
3533
3537
  setHistoryStore(store) {
3534
3538
  this.historyStore = store;
@@ -4429,8 +4433,8 @@ function formatToolSummary(name, rawInput, displaySummary) {
4429
4433
  }
4430
4434
  if (lowerName === "grep") {
4431
4435
  const pattern = args.pattern ?? "";
4432
- const path32 = args.path ?? "";
4433
- return pattern ? `\u{1F50D} Grep "${pattern}"${path32 ? ` in ${path32}` : ""}` : `\u{1F527} ${name}`;
4436
+ const path33 = args.path ?? "";
4437
+ return pattern ? `\u{1F50D} Grep "${pattern}"${path33 ? ` in ${path33}` : ""}` : `\u{1F527} ${name}`;
4434
4438
  }
4435
4439
  if (lowerName === "glob") {
4436
4440
  const pattern = args.pattern ?? "";
@@ -4466,8 +4470,8 @@ function formatToolTitle(name, rawInput, displayTitle) {
4466
4470
  }
4467
4471
  if (lowerName === "grep") {
4468
4472
  const pattern = args.pattern ?? "";
4469
- const path32 = args.path ?? "";
4470
- return pattern ? `"${pattern}"${path32 ? ` in ${path32}` : ""}` : name;
4473
+ const path33 = args.path ?? "";
4474
+ return pattern ? `"${pattern}"${path33 ? ` in ${path33}` : ""}` : name;
4471
4475
  }
4472
4476
  if (lowerName === "glob") {
4473
4477
  return String(args.pattern ?? name);
@@ -5608,12 +5612,12 @@ __export(version_exports, {
5608
5612
  runUpdate: () => runUpdate
5609
5613
  });
5610
5614
  import { fileURLToPath as fileURLToPath2 } from "url";
5611
- import { dirname as dirname11, join as join20, resolve as resolve5 } from "path";
5615
+ import { dirname as dirname11, join as join21, resolve as resolve5 } from "path";
5612
5616
  import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
5613
5617
  function findPackageJson() {
5614
5618
  let dir = dirname11(fileURLToPath2(import.meta.url));
5615
5619
  for (let i = 0; i < 5; i++) {
5616
- const candidate = join20(dir, "package.json");
5620
+ const candidate = join21(dir, "package.json");
5617
5621
  if (existsSync18(candidate)) return candidate;
5618
5622
  const parent = resolve5(dir, "..");
5619
5623
  if (parent === dir) break;
@@ -6451,7 +6455,7 @@ __export(integrate_exports, {
6451
6455
  uninstallIntegration: () => uninstallIntegration
6452
6456
  });
6453
6457
  import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync12, unlinkSync as unlinkSync7, chmodSync, rmdirSync } from "fs";
6454
- import { join as join21, dirname as dirname12 } from "path";
6458
+ import { join as join22, dirname as dirname12 } from "path";
6455
6459
  import { homedir as homedir10 } from "os";
6456
6460
  function expandPath(p) {
6457
6461
  return p.replace(/^~/, homedir10());
@@ -6653,30 +6657,30 @@ async function installIntegration(agentKey, spec) {
6653
6657
  }
6654
6658
  const hooksDir = expandPath(spec.hooksDirPath);
6655
6659
  mkdirSync12(hooksDir, { recursive: true });
6656
- const injectPath = join21(hooksDir, "openacp-inject-session.sh");
6660
+ const injectPath = join22(hooksDir, "openacp-inject-session.sh");
6657
6661
  writeFileSync12(injectPath, generateInjectScript(agentKey, spec));
6658
6662
  chmodSync(injectPath, 493);
6659
6663
  logs.push(`Created ${injectPath}`);
6660
- const handoffPath = join21(hooksDir, "openacp-handoff.sh");
6664
+ const handoffPath = join22(hooksDir, "openacp-handoff.sh");
6661
6665
  writeFileSync12(handoffPath, generateHandoffScript(agentKey));
6662
6666
  chmodSync(handoffPath, 493);
6663
6667
  logs.push(`Created ${handoffPath}`);
6664
6668
  if (spec.commandsPath && spec.handoffCommandName) {
6665
6669
  if (spec.commandFormat === "skill") {
6666
- const skillDir = expandPath(join21(spec.commandsPath, spec.handoffCommandName));
6670
+ const skillDir = expandPath(join22(spec.commandsPath, spec.handoffCommandName));
6667
6671
  mkdirSync12(skillDir, { recursive: true });
6668
- const skillPath = join21(skillDir, "SKILL.md");
6672
+ const skillPath = join22(skillDir, "SKILL.md");
6669
6673
  writeFileSync12(skillPath, generateHandoffCommand(agentKey, spec));
6670
6674
  logs.push(`Created ${skillPath}`);
6671
6675
  } else {
6672
6676
  const cmdsDir = expandPath(spec.commandsPath);
6673
6677
  mkdirSync12(cmdsDir, { recursive: true });
6674
- const cmdPath = join21(cmdsDir, `${spec.handoffCommandName}.md`);
6678
+ const cmdPath = join22(cmdsDir, `${spec.handoffCommandName}.md`);
6675
6679
  writeFileSync12(cmdPath, generateHandoffCommand(agentKey, spec));
6676
6680
  logs.push(`Created ${cmdPath}`);
6677
6681
  }
6678
6682
  }
6679
- const injectFullPath = join21(hooksDir, "openacp-inject-session.sh");
6683
+ const injectFullPath = join22(hooksDir, "openacp-inject-session.sh");
6680
6684
  if (spec.settingsFormat === "hooks_json") {
6681
6685
  mergeHooksJson(spec.settingsPath, spec.hookEvent, injectFullPath);
6682
6686
  } else {
@@ -6694,7 +6698,7 @@ async function uninstallIntegration(agentKey, spec) {
6694
6698
  try {
6695
6699
  const hooksDir = expandPath(spec.hooksDirPath);
6696
6700
  for (const filename of ["openacp-inject-session.sh", "openacp-handoff.sh"]) {
6697
- const filePath = join21(hooksDir, filename);
6701
+ const filePath = join22(hooksDir, filename);
6698
6702
  if (existsSync19(filePath)) {
6699
6703
  unlinkSync7(filePath);
6700
6704
  logs.push(`Removed ${filePath}`);
@@ -6702,8 +6706,8 @@ async function uninstallIntegration(agentKey, spec) {
6702
6706
  }
6703
6707
  if (spec.commandsPath && spec.handoffCommandName) {
6704
6708
  if (spec.commandFormat === "skill") {
6705
- const skillDir = expandPath(join21(spec.commandsPath, spec.handoffCommandName));
6706
- const skillPath = join21(skillDir, "SKILL.md");
6709
+ const skillDir = expandPath(join22(spec.commandsPath, spec.handoffCommandName));
6710
+ const skillPath = join22(skillDir, "SKILL.md");
6707
6711
  if (existsSync19(skillPath)) {
6708
6712
  unlinkSync7(skillPath);
6709
6713
  try {
@@ -6713,7 +6717,7 @@ async function uninstallIntegration(agentKey, spec) {
6713
6717
  logs.push(`Removed ${skillPath}`);
6714
6718
  }
6715
6719
  } else {
6716
- const cmdPath = expandPath(join21(spec.commandsPath, `${spec.handoffCommandName}.md`));
6720
+ const cmdPath = expandPath(join22(spec.commandsPath, `${spec.handoffCommandName}.md`));
6717
6721
  if (existsSync19(cmdPath)) {
6718
6722
  unlinkSync7(cmdPath);
6719
6723
  logs.push(`Removed ${cmdPath}`);
@@ -6739,7 +6743,7 @@ function buildHandoffItem(agentKey, spec) {
6739
6743
  name: "Handoff",
6740
6744
  description: "Transfer sessions between terminal and messaging platforms",
6741
6745
  isInstalled() {
6742
- return existsSync19(join21(hooksDir, "openacp-inject-session.sh")) && existsSync19(join21(hooksDir, "openacp-handoff.sh"));
6746
+ return existsSync19(join22(hooksDir, "openacp-inject-session.sh")) && existsSync19(join22(hooksDir, "openacp-handoff.sh"));
6743
6747
  },
6744
6748
  install: () => installIntegration(agentKey, spec),
6745
6749
  uninstall: () => uninstallIntegration(agentKey, spec)
@@ -6753,7 +6757,7 @@ function getSkillBasePath(spec) {
6753
6757
  function buildTunnelItem(spec) {
6754
6758
  if (!spec.commandsPath) return null;
6755
6759
  function getTunnelPath() {
6756
- return join21(getSkillBasePath(spec), "openacp-tunnel", "SKILL.md");
6760
+ return join22(getSkillBasePath(spec), "openacp-tunnel", "SKILL.md");
6757
6761
  }
6758
6762
  return {
6759
6763
  id: "tunnel",
@@ -15409,19 +15413,19 @@ init_doctor();
15409
15413
  init_config_registry();
15410
15414
 
15411
15415
  // src/core/config/config-editor.ts
15412
- import * as path26 from "path";
15416
+ import * as path27 from "path";
15413
15417
  import * as clack2 from "@clack/prompts";
15414
15418
 
15415
15419
  // src/cli/autostart.ts
15416
15420
  init_log();
15417
15421
  import { execFileSync as execFileSync5 } from "child_process";
15418
- import * as fs25 from "fs";
15419
- import * as path21 from "path";
15422
+ import * as fs26 from "fs";
15423
+ import * as path23 from "path";
15420
15424
  import * as os11 from "os";
15421
15425
  var log18 = createChildLogger({ module: "autostart" });
15422
15426
  var LAUNCHD_LABEL = "com.openacp.daemon";
15423
- var LAUNCHD_PLIST_PATH = path21.join(os11.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
15424
- var SYSTEMD_SERVICE_PATH = path21.join(os11.homedir(), ".config", "systemd", "user", "openacp.service");
15427
+ var LAUNCHD_PLIST_PATH = path23.join(os11.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
15428
+ var SYSTEMD_SERVICE_PATH = path23.join(os11.homedir(), ".config", "systemd", "user", "openacp.service");
15425
15429
  function isAutoStartSupported() {
15426
15430
  return process.platform === "darwin" || process.platform === "linux";
15427
15431
  }
@@ -15433,7 +15437,7 @@ function escapeSystemdValue(str) {
15433
15437
  return `"${escaped}"`;
15434
15438
  }
15435
15439
  function generateLaunchdPlist(nodePath, cliPath, logDir2) {
15436
- const logFile = path21.join(logDir2, "openacp.log");
15440
+ const logFile = path23.join(logDir2, "openacp.log");
15437
15441
  return `<?xml version="1.0" encoding="UTF-8"?>
15438
15442
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
15439
15443
  <plist version="1.0">
@@ -15478,23 +15482,23 @@ function installAutoStart(logDir2) {
15478
15482
  return { success: false, error: "Auto-start not supported on this platform" };
15479
15483
  }
15480
15484
  const nodePath = process.execPath;
15481
- const cliPath = path21.resolve(process.argv[1]);
15482
- const resolvedLogDir = logDir2.startsWith("~") ? path21.join(os11.homedir(), logDir2.slice(1)) : logDir2;
15485
+ const cliPath = path23.resolve(process.argv[1]);
15486
+ const resolvedLogDir = logDir2.startsWith("~") ? path23.join(os11.homedir(), logDir2.slice(1)) : logDir2;
15483
15487
  try {
15484
15488
  if (process.platform === "darwin") {
15485
15489
  const plist = generateLaunchdPlist(nodePath, cliPath, resolvedLogDir);
15486
- const dir = path21.dirname(LAUNCHD_PLIST_PATH);
15487
- fs25.mkdirSync(dir, { recursive: true });
15488
- fs25.writeFileSync(LAUNCHD_PLIST_PATH, plist);
15490
+ const dir = path23.dirname(LAUNCHD_PLIST_PATH);
15491
+ fs26.mkdirSync(dir, { recursive: true });
15492
+ fs26.writeFileSync(LAUNCHD_PLIST_PATH, plist);
15489
15493
  execFileSync5("launchctl", ["load", LAUNCHD_PLIST_PATH], { stdio: "pipe" });
15490
15494
  log18.info("LaunchAgent installed");
15491
15495
  return { success: true };
15492
15496
  }
15493
15497
  if (process.platform === "linux") {
15494
15498
  const unit = generateSystemdUnit(nodePath, cliPath);
15495
- const dir = path21.dirname(SYSTEMD_SERVICE_PATH);
15496
- fs25.mkdirSync(dir, { recursive: true });
15497
- fs25.writeFileSync(SYSTEMD_SERVICE_PATH, unit);
15499
+ const dir = path23.dirname(SYSTEMD_SERVICE_PATH);
15500
+ fs26.mkdirSync(dir, { recursive: true });
15501
+ fs26.writeFileSync(SYSTEMD_SERVICE_PATH, unit);
15498
15502
  execFileSync5("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
15499
15503
  execFileSync5("systemctl", ["--user", "enable", "openacp"], { stdio: "pipe" });
15500
15504
  log18.info("systemd user service installed");
@@ -15513,23 +15517,23 @@ function uninstallAutoStart() {
15513
15517
  }
15514
15518
  try {
15515
15519
  if (process.platform === "darwin") {
15516
- if (fs25.existsSync(LAUNCHD_PLIST_PATH)) {
15520
+ if (fs26.existsSync(LAUNCHD_PLIST_PATH)) {
15517
15521
  try {
15518
15522
  execFileSync5("launchctl", ["unload", LAUNCHD_PLIST_PATH], { stdio: "pipe" });
15519
15523
  } catch {
15520
15524
  }
15521
- fs25.unlinkSync(LAUNCHD_PLIST_PATH);
15525
+ fs26.unlinkSync(LAUNCHD_PLIST_PATH);
15522
15526
  log18.info("LaunchAgent removed");
15523
15527
  }
15524
15528
  return { success: true };
15525
15529
  }
15526
15530
  if (process.platform === "linux") {
15527
- if (fs25.existsSync(SYSTEMD_SERVICE_PATH)) {
15531
+ if (fs26.existsSync(SYSTEMD_SERVICE_PATH)) {
15528
15532
  try {
15529
15533
  execFileSync5("systemctl", ["--user", "disable", "openacp"], { stdio: "pipe" });
15530
15534
  } catch {
15531
15535
  }
15532
- fs25.unlinkSync(SYSTEMD_SERVICE_PATH);
15536
+ fs26.unlinkSync(SYSTEMD_SERVICE_PATH);
15533
15537
  execFileSync5("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
15534
15538
  log18.info("systemd user service removed");
15535
15539
  }
@@ -15544,10 +15548,10 @@ function uninstallAutoStart() {
15544
15548
  }
15545
15549
  function isAutoStartInstalled() {
15546
15550
  if (process.platform === "darwin") {
15547
- return fs25.existsSync(LAUNCHD_PLIST_PATH);
15551
+ return fs26.existsSync(LAUNCHD_PLIST_PATH);
15548
15552
  }
15549
15553
  if (process.platform === "linux") {
15550
- return fs25.existsSync(SYSTEMD_SERVICE_PATH);
15554
+ return fs26.existsSync(SYSTEMD_SERVICE_PATH);
15551
15555
  }
15552
15556
  return false;
15553
15557
  }
@@ -15752,7 +15756,7 @@ async function editDiscord(_config, _updates) {
15752
15756
  const { createInstallContext: createInstallContext2 } = await Promise.resolve().then(() => (init_install_context(), install_context_exports));
15753
15757
  const { getGlobalRoot: getGlobalRoot2 } = await Promise.resolve().then(() => (init_instance_context(), instance_context_exports));
15754
15758
  const root = getGlobalRoot2();
15755
- const basePath = path26.join(root, "plugins");
15759
+ const basePath = path27.join(root, "plugins", "data");
15756
15760
  const settingsManager = new SettingsManager2(basePath);
15757
15761
  const ctx = createInstallContext2({
15758
15762
  pluginName: plugin.name,
@@ -15766,11 +15770,17 @@ async function editDiscord(_config, _updates) {
15766
15770
  }
15767
15771
  }
15768
15772
  async function editChannels(config, updates, settingsManager) {
15769
- const tgEnabled = config.channels?.telegram?.enabled !== false && config.channels?.telegram;
15770
- const dcEnabled = config.channels?.discord?.enabled !== false && config.channels?.discord;
15773
+ let tgConfigured = !!config.channels?.telegram;
15774
+ let dcConfigured = !!config.channels?.discord;
15775
+ if (settingsManager) {
15776
+ const tgPs = await settingsManager.loadSettings("@openacp/telegram");
15777
+ if (tgPs.botToken && tgPs.chatId) tgConfigured = true;
15778
+ const dcPs = await settingsManager.loadSettings("@openacp/adapter-discord");
15779
+ if (dcPs.guildId || dcPs.token) dcConfigured = true;
15780
+ }
15771
15781
  console.log(header("Channels"));
15772
- console.log(` Telegram : ${tgEnabled ? ok("configured") : dim("not configured")}`);
15773
- console.log(` Discord : ${dcEnabled ? ok("configured") : dim("not configured")}`);
15782
+ console.log(` Telegram : ${tgConfigured ? ok("configured") : dim("not configured")}`);
15783
+ console.log(` Discord : ${dcConfigured ? ok("configured") : dim("not configured")}`);
15774
15784
  console.log("");
15775
15785
  while (true) {
15776
15786
  const choice = await select3({
@@ -16267,17 +16277,17 @@ ${c.cyan}${c.bold}OpenACP Config Editor${c.reset}`);
16267
16277
  async function sendConfigViaApi(port, updates) {
16268
16278
  const { apiCall: call } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
16269
16279
  const paths = flattenToPaths(updates);
16270
- for (const { path: path32, value } of paths) {
16280
+ for (const { path: path33, value } of paths) {
16271
16281
  const res = await call(port, "/api/config", {
16272
16282
  method: "PATCH",
16273
16283
  headers: { "Content-Type": "application/json" },
16274
- body: JSON.stringify({ path: path32, value })
16284
+ body: JSON.stringify({ path: path33, value })
16275
16285
  });
16276
16286
  const data = await res.json();
16277
16287
  if (!res.ok) {
16278
- console.log(warn(`Failed to update ${path32}: ${data.error}`));
16288
+ console.log(warn(`Failed to update ${path33}: ${data.error}`));
16279
16289
  } else if (data.needsRestart) {
16280
- console.log(warn(`${path32} updated \u2014 restart required`));
16290
+ console.log(warn(`${path33} updated \u2014 restart required`));
16281
16291
  }
16282
16292
  }
16283
16293
  }
@@ -16298,23 +16308,23 @@ function flattenToPaths(obj, prefix = "") {
16298
16308
  init_config();
16299
16309
  import { spawn as spawn3 } from "child_process";
16300
16310
  import * as fs29 from "fs";
16301
- import * as path27 from "path";
16311
+ import * as path28 from "path";
16302
16312
  import * as os14 from "os";
16303
- var DEFAULT_ROOT2 = path27.join(os14.homedir(), ".openacp");
16313
+ var DEFAULT_ROOT2 = path28.join(os14.homedir(), ".openacp");
16304
16314
  function getPidPath(root) {
16305
16315
  const base = root ?? DEFAULT_ROOT2;
16306
- return path27.join(base, "openacp.pid");
16316
+ return path28.join(base, "openacp.pid");
16307
16317
  }
16308
16318
  function getLogDir(root) {
16309
16319
  const base = root ?? DEFAULT_ROOT2;
16310
- return path27.join(base, "logs");
16320
+ return path28.join(base, "logs");
16311
16321
  }
16312
16322
  function getRunningMarker(root) {
16313
16323
  const base = root ?? DEFAULT_ROOT2;
16314
- return path27.join(base, "running");
16324
+ return path28.join(base, "running");
16315
16325
  }
16316
16326
  function writePidFile(pidPath, pid) {
16317
- const dir = path27.dirname(pidPath);
16327
+ const dir = path28.dirname(pidPath);
16318
16328
  fs29.mkdirSync(dir, { recursive: true });
16319
16329
  fs29.writeFileSync(pidPath, String(pid));
16320
16330
  }
@@ -16363,8 +16373,8 @@ function startDaemon(pidPath = getPidPath(), logDir2, instanceRoot) {
16363
16373
  }
16364
16374
  const resolvedLogDir = logDir2 ? expandHome3(logDir2) : getLogDir(instanceRoot);
16365
16375
  fs29.mkdirSync(resolvedLogDir, { recursive: true });
16366
- const logFile = path27.join(resolvedLogDir, "openacp.log");
16367
- const cliPath = path27.resolve(process.argv[1]);
16376
+ const logFile = path28.join(resolvedLogDir, "openacp.log");
16377
+ const cliPath = path28.resolve(process.argv[1]);
16368
16378
  const nodePath = process.execPath;
16369
16379
  const out = fs29.openSync(logFile, "a");
16370
16380
  const err = fs29.openSync(logFile, "a");
@@ -16448,7 +16458,7 @@ async function stopDaemon(pidPath = getPidPath(), instanceRoot) {
16448
16458
  }
16449
16459
  function markRunning(root) {
16450
16460
  const marker = getRunningMarker(root);
16451
- fs29.mkdirSync(path27.dirname(marker), { recursive: true });
16461
+ fs29.mkdirSync(path28.dirname(marker), { recursive: true });
16452
16462
  fs29.writeFileSync(marker, "");
16453
16463
  }
16454
16464
  function clearRunning(root) {