@okxweb3/a2a-node 0.1.4 → 0.1.6-beta-c3024b2b0b-260706164140

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.
Files changed (3) hide show
  1. package/dist/cli.js +375 -266
  2. package/dist/index.js +902 -773
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1697,6 +1697,520 @@ var init_session_store = __esm({
1697
1697
  }
1698
1698
  });
1699
1699
 
1700
+ // src/daemon-lock.ts
1701
+ function isProcessAlive(pid) {
1702
+ try {
1703
+ process.kill(pid, 0);
1704
+ return true;
1705
+ } catch (err2) {
1706
+ return err2.code === "EPERM";
1707
+ }
1708
+ }
1709
+ function ownerPath(lockPath) {
1710
+ return (0, import_node_path4.join)(lockPath, OWNER_FILE);
1711
+ }
1712
+ async function readDaemonLock(lockPath) {
1713
+ let metadata = null;
1714
+ try {
1715
+ const raw = await (0, import_promises.readFile)(ownerPath(lockPath), "utf8");
1716
+ metadata = JSON.parse(raw);
1717
+ } catch (err2) {
1718
+ const code2 = err2.code;
1719
+ if (code2 === "ENOENT") {
1720
+ try {
1721
+ const info = await (0, import_promises.stat)(lockPath);
1722
+ const stale = Date.now() - info.mtimeMs > EMPTY_LOCK_STALE_MS;
1723
+ return { metadata: null, running: !stale, stale, path: lockPath };
1724
+ } catch (statErr) {
1725
+ const statCode = statErr.code;
1726
+ if (statCode === "ENOENT") {
1727
+ return { metadata: null, running: false, stale: false, path: lockPath };
1728
+ }
1729
+ throw statErr;
1730
+ }
1731
+ }
1732
+ if (err2 instanceof SyntaxError) {
1733
+ return { metadata: null, running: false, stale: true, path: lockPath };
1734
+ }
1735
+ throw err2;
1736
+ }
1737
+ const running = Number.isInteger(metadata.pid) && metadata.pid > 0 && isProcessAlive(metadata.pid);
1738
+ return { metadata, running, stale: !running, path: lockPath };
1739
+ }
1740
+ async function markDaemonReady(lockPath) {
1741
+ const current = await readDaemonLock(lockPath);
1742
+ const metadata = current.metadata;
1743
+ if (!metadata || metadata.pid !== process.pid) {
1744
+ return;
1745
+ }
1746
+ await (0, import_promises.writeFile)(ownerPath(lockPath), `${JSON.stringify({
1747
+ ...metadata,
1748
+ ready: true,
1749
+ readyAt: (/* @__PURE__ */ new Date()).toISOString()
1750
+ }, null, 2)}
1751
+ `, "utf8");
1752
+ }
1753
+ async function removeLock(lockPath) {
1754
+ await (0, import_promises.rm)(lockPath, { recursive: true, force: true });
1755
+ }
1756
+ async function acquireDaemonLock(paths, entry) {
1757
+ const metadata = {
1758
+ pid: process.pid,
1759
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1760
+ cwd: process.cwd(),
1761
+ entry,
1762
+ homeDir: paths.homeDir,
1763
+ capabilities: DAEMON_CAPABILITIES,
1764
+ ready: false
1765
+ };
1766
+ ensureTaskDir(paths.runDir);
1767
+ for (let attempt = 0; attempt < 2; attempt += 1) {
1768
+ try {
1769
+ await (0, import_promises.mkdir)(paths.daemonLockPath, { mode: A2A_TASK_DIR_MODE });
1770
+ await chmodBestEffort(paths.daemonLockPath, A2A_TASK_DIR_MODE);
1771
+ await (0, import_promises.writeFile)(ownerPath(paths.daemonLockPath), `${JSON.stringify(metadata, null, 2)}
1772
+ `, "utf8");
1773
+ return {
1774
+ metadata,
1775
+ release: async () => {
1776
+ const current = await readDaemonLock(paths.daemonLockPath);
1777
+ if (current.metadata?.pid === process.pid) {
1778
+ await removeLock(paths.daemonLockPath);
1779
+ }
1780
+ }
1781
+ };
1782
+ } catch (err2) {
1783
+ const code2 = err2.code;
1784
+ if (code2 !== "EEXIST") {
1785
+ throw err2;
1786
+ }
1787
+ const current = await readDaemonLock(paths.daemonLockPath);
1788
+ if (current.running) {
1789
+ return null;
1790
+ }
1791
+ if (!current.stale) {
1792
+ return null;
1793
+ }
1794
+ await removeLock(paths.daemonLockPath);
1795
+ }
1796
+ }
1797
+ return null;
1798
+ }
1799
+ async function chmodBestEffort(path, mode) {
1800
+ try {
1801
+ await (0, import_promises.chmod)(path, mode);
1802
+ } catch (err2) {
1803
+ const code2 = err2.code;
1804
+ if (code2 !== "EPERM" && code2 !== "EACCES") {
1805
+ throw err2;
1806
+ }
1807
+ }
1808
+ }
1809
+ var import_promises, import_node_path4, OWNER_FILE, EMPTY_LOCK_STALE_MS, DAEMON_CAPABILITY_AI_DISPATCH, DAEMON_CAPABILITIES;
1810
+ var init_daemon_lock = __esm({
1811
+ "src/daemon-lock.ts"() {
1812
+ "use strict";
1813
+ import_promises = require("node:fs/promises");
1814
+ import_node_path4 = require("node:path");
1815
+ init_paths();
1816
+ init_a2a_paths();
1817
+ OWNER_FILE = "owner.json";
1818
+ EMPTY_LOCK_STALE_MS = 1e4;
1819
+ DAEMON_CAPABILITY_AI_DISPATCH = "ai-dispatch";
1820
+ DAEMON_CAPABILITIES = [
1821
+ DAEMON_CAPABILITY_AI_DISPATCH
1822
+ ];
1823
+ }
1824
+ });
1825
+
1826
+ // src/daemon.ts
1827
+ var daemon_exports = {};
1828
+ __export(daemon_exports, {
1829
+ ensureDaemonReady: () => ensureDaemonReady,
1830
+ getDaemonStatus: () => getDaemonStatus,
1831
+ startDaemon: () => startDaemon,
1832
+ stopDaemon: () => stopDaemon
1833
+ });
1834
+ async function readPid(pidPath) {
1835
+ try {
1836
+ const raw = await (0, import_promises2.readFile)(pidPath, "utf8");
1837
+ const pid = Number.parseInt(raw.trim(), 10);
1838
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
1839
+ } catch (err2) {
1840
+ const code2 = err2.code;
1841
+ if (code2 === "ENOENT") {
1842
+ return null;
1843
+ }
1844
+ throw err2;
1845
+ }
1846
+ }
1847
+ async function removePid(pidPath) {
1848
+ try {
1849
+ await (0, import_promises2.unlink)(pidPath);
1850
+ } catch (err2) {
1851
+ const code2 = err2.code;
1852
+ if (code2 !== "ENOENT") {
1853
+ throw err2;
1854
+ }
1855
+ }
1856
+ }
1857
+ async function ensureDaemonDirs(homeDir) {
1858
+ const paths = resolveTaskPaths(homeDir);
1859
+ ensureTaskDir(paths.jobsDir);
1860
+ ensureTaskDir(paths.runDir);
1861
+ ensureTaskDir(paths.logsDir);
1862
+ ensureTaskDir(paths.commandsDir);
1863
+ ensureTaskDir(paths.downloadsDir);
1864
+ ensureTaskDir(paths.xmtpDir);
1865
+ ensureTaskDir(paths.sqliteDir);
1866
+ return paths;
1867
+ }
1868
+ async function ensureAiWorkspace(paths) {
1869
+ const aiWorkingDir = paths.workspaceDir;
1870
+ await (0, import_promises2.rm)(aiWorkingDir, { recursive: true, force: true });
1871
+ ensureTaskDir(aiWorkingDir);
1872
+ return aiWorkingDir;
1873
+ }
1874
+ async function waitForImmediateExit(child, timeoutMs) {
1875
+ return await new Promise((resolve6) => {
1876
+ let timer;
1877
+ const onExit = () => {
1878
+ clearTimeout(timer);
1879
+ resolve6(true);
1880
+ };
1881
+ timer = setTimeout(() => {
1882
+ child.off("exit", onExit);
1883
+ resolve6(false);
1884
+ }, timeoutMs);
1885
+ child.once("exit", onExit);
1886
+ });
1887
+ }
1888
+ async function getDaemonStatus(homeDir) {
1889
+ const paths = resolveTaskPaths(homeDir);
1890
+ const pid = await readPid(paths.pidPath);
1891
+ const lock = await readDaemonLock(paths.daemonLockPath);
1892
+ const lockPid = lock.metadata?.pid ?? null;
1893
+ const lockReadyStateKnown = !!lock.metadata && (typeof lock.metadata.ready === "boolean" || typeof lock.metadata.readyAt === "string");
1894
+ const lockReady = lockReadyStateKnown ? lock.metadata?.ready === true || typeof lock.metadata?.readyAt === "string" : true;
1895
+ if (lock.running) {
1896
+ return {
1897
+ running: true,
1898
+ pid: lockPid ?? pid,
1899
+ stale: false,
1900
+ capabilities: lock.metadata?.capabilities ?? [],
1901
+ ready: lockReady,
1902
+ readyAt: lock.metadata?.readyAt ?? null,
1903
+ readyStateKnown: lockReadyStateKnown,
1904
+ pidPath: paths.pidPath,
1905
+ lockPath: paths.daemonLockPath,
1906
+ lockPid,
1907
+ lockStale: false
1908
+ };
1909
+ }
1910
+ if (!pid) {
1911
+ return {
1912
+ running: false,
1913
+ pid: null,
1914
+ stale: lock.stale,
1915
+ capabilities: [],
1916
+ ready: false,
1917
+ readyAt: null,
1918
+ readyStateKnown: false,
1919
+ pidPath: paths.pidPath,
1920
+ lockPath: paths.daemonLockPath,
1921
+ lockPid,
1922
+ lockStale: lock.stale
1923
+ };
1924
+ }
1925
+ const running = isProcessAlive(pid);
1926
+ return {
1927
+ running,
1928
+ pid,
1929
+ stale: !running || lock.stale,
1930
+ capabilities: running ? lock.metadata?.capabilities ?? [] : [],
1931
+ ready: running && !lockReadyStateKnown ? true : running && lockReady,
1932
+ readyAt: running ? lock.metadata?.readyAt ?? null : null,
1933
+ readyStateKnown: running && lockReadyStateKnown,
1934
+ pidPath: paths.pidPath,
1935
+ lockPath: paths.daemonLockPath,
1936
+ lockPid,
1937
+ lockStale: lock.stale
1938
+ };
1939
+ }
1940
+ async function startDaemon(homeDir) {
1941
+ const paths = await ensureDaemonDirs(homeDir);
1942
+ const aiWorkingDir = await ensureAiWorkspace(paths);
1943
+ const current = await getDaemonStatus(homeDir);
1944
+ if (current.running) {
1945
+ return {
1946
+ ...current,
1947
+ started: false,
1948
+ logPath: paths.listenerLogPath
1949
+ };
1950
+ }
1951
+ if (current.stale) {
1952
+ await removePid(paths.pidPath);
1953
+ }
1954
+ const store = new SessionStore({ homeDir });
1955
+ try {
1956
+ store.setSetting("ai_working_dir", aiWorkingDir);
1957
+ store.resetGlobalSession(SYSTEM_NOTIFICATION_SESSION_KEY);
1958
+ } finally {
1959
+ store.close();
1960
+ }
1961
+ const logFd = (0, import_node_fs3.openSync)(paths.listenerLogPath, "a");
1962
+ const entry = process.env.OKX_AGENT_TASK_CLI_PATH || (0, import_node_path5.join)(__dirname, "cli.js");
1963
+ const daemonCwd = (0, import_node_path5.join)(__dirname, "..");
1964
+ const child = (0, import_node_child_process.spawn)(process.execPath, [entry, "run"], {
1965
+ cwd: daemonCwd,
1966
+ detached: true,
1967
+ // win32: keep the detached daemon from flashing/holding a console window.
1968
+ // Ignored on every non-win32 platform.
1969
+ windowsHide: true,
1970
+ env: {
1971
+ ...process.env,
1972
+ OKX_AGENT_TASK_HOME: paths.homeDir,
1973
+ OKX_AGENT_TASK_DAEMON: "1",
1974
+ OKX_A2A_AI_CWD: aiWorkingDir,
1975
+ OKX_AGENT_TASK_AI_CWD: aiWorkingDir
1976
+ },
1977
+ stdio: ["ignore", logFd, logFd]
1978
+ });
1979
+ (0, import_node_fs3.closeSync)(logFd);
1980
+ child.unref();
1981
+ await (0, import_promises2.writeFile)(paths.pidPath, `${child.pid ?? ""}
1982
+ `, "utf8");
1983
+ if (await waitForImmediateExit(child, START_EXIT_CHECK_MS)) {
1984
+ const status = await getDaemonStatus(homeDir);
1985
+ if (status.running && status.lockPid) {
1986
+ await (0, import_promises2.writeFile)(paths.pidPath, `${status.lockPid}
1987
+ `, "utf8");
1988
+ } else {
1989
+ await removePid(paths.pidPath);
1990
+ }
1991
+ return {
1992
+ ...status,
1993
+ started: false,
1994
+ logPath: paths.listenerLogPath
1995
+ };
1996
+ }
1997
+ return {
1998
+ running: true,
1999
+ pid: child.pid ?? null,
2000
+ stale: false,
2001
+ capabilities: DAEMON_CAPABILITIES,
2002
+ ready: false,
2003
+ readyAt: null,
2004
+ readyStateKnown: true,
2005
+ pidPath: paths.pidPath,
2006
+ lockPath: paths.daemonLockPath,
2007
+ lockPid: child.pid ?? null,
2008
+ lockStale: false,
2009
+ started: true,
2010
+ logPath: paths.listenerLogPath
2011
+ };
2012
+ }
2013
+ async function waitForExit(pid, timeoutMs) {
2014
+ const deadline = Date.now() + timeoutMs;
2015
+ while (Date.now() < deadline) {
2016
+ if (!isProcessAlive(pid)) {
2017
+ return true;
2018
+ }
2019
+ await new Promise((resolve6) => setTimeout(resolve6, 100));
2020
+ }
2021
+ return !isProcessAlive(pid);
2022
+ }
2023
+ function signalProcess(pid, signal) {
2024
+ try {
2025
+ process.kill(pid, signal);
2026
+ return true;
2027
+ } catch (err2) {
2028
+ const code2 = err2.code;
2029
+ if (code2 === "ESRCH") {
2030
+ return false;
2031
+ }
2032
+ throw err2;
2033
+ }
2034
+ }
2035
+ async function stopDaemon(homeDir) {
2036
+ const paths = resolveTaskPaths(homeDir);
2037
+ const current = await getDaemonStatus(homeDir);
2038
+ if (!current.pid) {
2039
+ return { ...current, stopped: false };
2040
+ }
2041
+ if (!current.running) {
2042
+ await removePid(paths.pidPath);
2043
+ return {
2044
+ running: false,
2045
+ pid: current.pid,
2046
+ stale: false,
2047
+ capabilities: [],
2048
+ ready: false,
2049
+ readyAt: null,
2050
+ readyStateKnown: false,
2051
+ pidPath: paths.pidPath,
2052
+ lockPath: paths.daemonLockPath,
2053
+ lockPid: current.lockPid,
2054
+ lockStale: current.lockStale,
2055
+ stopped: false
2056
+ };
2057
+ }
2058
+ const signalled = signalProcess(current.pid, "SIGTERM");
2059
+ let forced = false;
2060
+ let exited = !signalled || await waitForExit(current.pid, STOP_GRACE_MS);
2061
+ if (!exited) {
2062
+ forced = true;
2063
+ const killed = signalProcess(current.pid, "SIGKILL");
2064
+ exited = !killed || await waitForExit(current.pid, FORCE_KILL_GRACE_MS);
2065
+ }
2066
+ if (exited) {
2067
+ await removePid(paths.pidPath);
2068
+ }
2069
+ return {
2070
+ running: !exited,
2071
+ pid: current.pid,
2072
+ stale: false,
2073
+ capabilities: exited ? [] : current.capabilities,
2074
+ ready: !exited && current.ready,
2075
+ readyAt: !exited ? current.readyAt : null,
2076
+ readyStateKnown: !exited && current.readyStateKnown,
2077
+ pidPath: paths.pidPath,
2078
+ lockPath: paths.daemonLockPath,
2079
+ lockPid: current.lockPid,
2080
+ lockStale: current.lockStale,
2081
+ stopped: exited,
2082
+ forced
2083
+ };
2084
+ }
2085
+ async function ensureDaemonReady(options = {}) {
2086
+ const paths = resolveTaskPaths(options.homeDir);
2087
+ const commandName = options.commandName ?? "command";
2088
+ const timeoutMs = options.timeoutMs ?? readReadyTimeoutMs(options.env ?? process.env);
2089
+ let status = await getDaemonStatus(options.homeDir);
2090
+ let started = false;
2091
+ let logPath = paths.listenerLogPath;
2092
+ if (!status.running) {
2093
+ options.stderr?.write(`[okx-a2a] ${commandName} requires the daemon; starting daemon...
2094
+ `);
2095
+ const startResult = await startDaemon(options.homeDir);
2096
+ started = startResult.started;
2097
+ logPath = startResult.logPath;
2098
+ status = startResult;
2099
+ if (!status.running) {
2100
+ throw new Error(
2101
+ `${commandName} requires the daemon, but automatic daemon start failed. Check ${logPath} or run \`okx-a2a daemon restart\`.`
2102
+ );
2103
+ }
2104
+ status = await waitForDaemonReady({
2105
+ homeDir: options.homeDir,
2106
+ timeoutMs,
2107
+ requiredCapabilities: options.requiredCapabilities,
2108
+ requireKnownReadyState: true,
2109
+ logPath,
2110
+ commandName
2111
+ });
2112
+ options.stderr?.write(`[okx-a2a] daemon ready pid=${status.pid ?? "(unknown)"} log=${logPath}
2113
+ `);
2114
+ } else if (status.readyStateKnown && !status.ready) {
2115
+ status = await waitForDaemonReady({
2116
+ homeDir: options.homeDir,
2117
+ timeoutMs,
2118
+ requiredCapabilities: options.requiredCapabilities,
2119
+ requireKnownReadyState: false,
2120
+ logPath,
2121
+ commandName
2122
+ });
2123
+ }
2124
+ assertRequiredCapabilities(status, options.requiredCapabilities, commandName);
2125
+ return {
2126
+ ...status,
2127
+ started,
2128
+ logPath
2129
+ };
2130
+ }
2131
+ async function waitForDaemonReady(options) {
2132
+ const deadline = Date.now() + Math.max(0, options.timeoutMs);
2133
+ let lastStatus = await getDaemonStatus(options.homeDir);
2134
+ while (Date.now() <= deadline) {
2135
+ const status = await getDaemonStatus(options.homeDir);
2136
+ lastStatus = status;
2137
+ if (!status.running) {
2138
+ if (status.stale) {
2139
+ throw new Error(
2140
+ `${options.commandName} requires the daemon, but the daemon exited before becoming ready. Check ${options.logPath} or run \`okx-a2a daemon restart\`.`
2141
+ );
2142
+ }
2143
+ } else if (isReadyForCommand(status, options.requiredCapabilities, options.requireKnownReadyState)) {
2144
+ return status;
2145
+ } else if (status.ready && findMissingCapabilities(status, options.requiredCapabilities).length > 0) {
2146
+ assertRequiredCapabilities(status, options.requiredCapabilities, options.commandName);
2147
+ }
2148
+ await sleep(Math.min(READY_POLL_MS, Math.max(1, deadline - Date.now() + 1)));
2149
+ }
2150
+ const missing = findMissingCapabilities(lastStatus, options.requiredCapabilities);
2151
+ const capabilitySuffix = missing.length > 0 ? ` missingCapabilities=${missing.join(",")}` : "";
2152
+ throw new Error(
2153
+ `${options.commandName} requires the daemon, but it did not become ready within ${options.timeoutMs}ms${capabilitySuffix}. Check ${options.logPath} or run \`okx-a2a daemon restart\`.`
2154
+ );
2155
+ }
2156
+ function isReadyForCommand(status, requiredCapabilities, requireKnownReadyState = false) {
2157
+ if (!status.running) {
2158
+ return false;
2159
+ }
2160
+ if (requireKnownReadyState && !status.readyStateKnown) {
2161
+ return false;
2162
+ }
2163
+ if (status.readyStateKnown && !status.ready) {
2164
+ return false;
2165
+ }
2166
+ return findMissingCapabilities(status, requiredCapabilities).length === 0;
2167
+ }
2168
+ function assertRequiredCapabilities(status, requiredCapabilities, commandName) {
2169
+ const missing = findMissingCapabilities(status, requiredCapabilities);
2170
+ if (missing.length === 0) {
2171
+ return;
2172
+ }
2173
+ throw new Error(
2174
+ `${commandName} requires a daemon with ${missing.join(",")} support. Run \`okx-a2a daemon restart\` first.`
2175
+ );
2176
+ }
2177
+ function findMissingCapabilities(status, requiredCapabilities) {
2178
+ if (!requiredCapabilities || requiredCapabilities.length === 0) {
2179
+ return [];
2180
+ }
2181
+ return requiredCapabilities.filter((capability) => !status.capabilities.includes(capability));
2182
+ }
2183
+ function readReadyTimeoutMs(env) {
2184
+ const raw = env[DAEMON_READY_TIMEOUT_ENV]?.trim();
2185
+ if (!raw) {
2186
+ return DEFAULT_READY_TIMEOUT_MS;
2187
+ }
2188
+ const parsed = Number(raw);
2189
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_READY_TIMEOUT_MS;
2190
+ }
2191
+ function sleep(ms) {
2192
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
2193
+ }
2194
+ var import_node_fs3, import_promises2, import_node_child_process, import_node_path5, STOP_GRACE_MS, FORCE_KILL_GRACE_MS, START_EXIT_CHECK_MS, DEFAULT_READY_TIMEOUT_MS, READY_POLL_MS, DAEMON_READY_TIMEOUT_ENV;
2195
+ var init_daemon = __esm({
2196
+ "src/daemon.ts"() {
2197
+ "use strict";
2198
+ import_node_fs3 = require("node:fs");
2199
+ import_promises2 = require("node:fs/promises");
2200
+ import_node_child_process = require("node:child_process");
2201
+ import_node_path5 = require("node:path");
2202
+ init_paths();
2203
+ init_session_store();
2204
+ init_daemon_lock();
2205
+ STOP_GRACE_MS = 5e3;
2206
+ FORCE_KILL_GRACE_MS = 5e3;
2207
+ START_EXIT_CHECK_MS = 750;
2208
+ DEFAULT_READY_TIMEOUT_MS = 12e4;
2209
+ READY_POLL_MS = 250;
2210
+ DAEMON_READY_TIMEOUT_ENV = "OKX_A2A_DAEMON_READY_TIMEOUT_MS";
2211
+ }
2212
+ });
2213
+
1700
2214
  // ../core/src/log.ts
1701
2215
  function formatLogTimestamp(date = /* @__PURE__ */ new Date()) {
1702
2216
  return date.toLocaleString(void 0, {
@@ -2228,11 +2742,25 @@ function switchProvider(options) {
2228
2742
  readParentProcessCommand: options.readParentProcessCommand
2229
2743
  });
2230
2744
  if (runtime === "unknown") {
2745
+ const stored = options.store.getDefaultAiProvider();
2746
+ if (stored) {
2747
+ return {
2748
+ ok: true,
2749
+ runtime: "unknown",
2750
+ provider: stored,
2751
+ previousProvider: stored,
2752
+ changed: false,
2753
+ action: "kept_existing",
2754
+ userMessage: `No AI runtime detected for the current environment; keeping the existing default provider (${formatAiProviderDisplayName(stored)}).`
2755
+ };
2756
+ }
2231
2757
  return {
2232
2758
  ok: false,
2233
2759
  runtime: "unknown",
2234
2760
  reason: "unknown_runtime",
2235
- message: "Could not determine the current AI provider."
2761
+ state: "blocked",
2762
+ message: "Could not determine the current AI provider.",
2763
+ userMessage: "Could not detect the current AI runtime and no default AI provider is configured. Run this from your AI environment (OpenClaw / Codex / Claude / Hermes), or set a provider manually: `okx-a2a ai-provider set --provider <codex|claude|hermes|openclaw>`."
2236
2764
  };
2237
2765
  }
2238
2766
  const previousProvider = options.store.getDefaultAiProvider();
@@ -2244,6 +2772,7 @@ function switchProvider(options) {
2244
2772
  provider: runtime,
2245
2773
  previousProvider,
2246
2774
  changed,
2775
+ action: "switched",
2247
2776
  userMessage: changed ? `Switched to ${formatAiProviderDisplayName(runtime)}\uFF5CNew tasks will be handled here; unfinished tasks should be continued in their original session` : ""
2248
2777
  };
2249
2778
  }
@@ -70893,6 +71422,207 @@ var require_ws = __commonJS({
70893
71422
  }
70894
71423
  });
70895
71424
 
71425
+ // src/win-native-launcher.ts
71426
+ var win_native_launcher_exports = {};
71427
+ __export(win_native_launcher_exports, {
71428
+ NATIVE_LAUNCHER_EXE_NAME: () => NATIVE_LAUNCHER_EXE_NAME,
71429
+ buildLauncherEntryJs: () => buildLauncherEntryJs,
71430
+ buildSeaConfig: () => buildSeaConfig,
71431
+ ensureWindowsNativeLauncher: () => ensureWindowsNativeLauncher,
71432
+ findWindowsNativeOkxA2aExe: () => findWindowsNativeOkxA2aExe,
71433
+ installWindowsNativeLauncher: () => installWindowsNativeLauncher,
71434
+ resolveRunningCliPath: () => resolveRunningCliPath
71435
+ });
71436
+ function isPostjectRunnable() {
71437
+ try {
71438
+ const probe = spawnSyncCompat(POSTJECT_BIN, ["--help"], {
71439
+ stdio: "ignore",
71440
+ windowsHide: true,
71441
+ timeout: 3e4
71442
+ });
71443
+ return probe.status === 0;
71444
+ } catch {
71445
+ return false;
71446
+ }
71447
+ }
71448
+ function resolvePostjectCommand() {
71449
+ try {
71450
+ const cliPath = (0, import_node_module.createRequire)(__filename).resolve("postject/dist/cli.js");
71451
+ if ((0, import_node_fs16.existsSync)(cliPath)) {
71452
+ return { command: process.execPath, prefixArgs: [cliPath] };
71453
+ }
71454
+ } catch {
71455
+ }
71456
+ if (!isPostjectRunnable()) {
71457
+ logWinCompat(`${WIN_COMPAT_LOG_PREFIX} native launcher: installing ${POSTJECT_SPEC} globally`);
71458
+ const install = spawnSyncCompat("npm", [
71459
+ "install",
71460
+ "-g",
71461
+ POSTJECT_SPEC,
71462
+ "--no-audit",
71463
+ "--no-fund",
71464
+ "--loglevel=error"
71465
+ ], { encoding: "utf8", windowsHide: true, timeout: 18e4 });
71466
+ if (install.status !== 0 || !isPostjectRunnable()) {
71467
+ throw new Error(
71468
+ `failed to install ${POSTJECT_SPEC} (needed to build okx-a2a.exe): ${String(install.stderr || install.error?.message || "unknown error").slice(0, 300)}`
71469
+ );
71470
+ }
71471
+ }
71472
+ return { command: POSTJECT_BIN, prefixArgs: [] };
71473
+ }
71474
+ function injectSeaBlob(exePath, blobPath, isMac) {
71475
+ const { command, prefixArgs: prefixArgs2 } = resolvePostjectCommand();
71476
+ const args = [
71477
+ ...prefixArgs2,
71478
+ exePath,
71479
+ "NODE_SEA_BLOB",
71480
+ blobPath,
71481
+ "--sentinel-fuse",
71482
+ SEA_SENTINEL_FUSE,
71483
+ "--overwrite"
71484
+ ];
71485
+ if (isMac) {
71486
+ args.push("--macho-segment-name", "NODE_SEA");
71487
+ }
71488
+ const result = spawnSyncCompat(command, args, {
71489
+ encoding: "utf8",
71490
+ windowsHide: true,
71491
+ timeout: 12e4
71492
+ });
71493
+ if (result.status !== 0) {
71494
+ throw new Error(
71495
+ `postject injection failed: ${String(result.stderr || result.error?.message || `exit ${result.status}`).slice(0, 300)}`
71496
+ );
71497
+ }
71498
+ }
71499
+ function buildLauncherEntryJs(cliPath) {
71500
+ const target = JSON.stringify(cliPath);
71501
+ return [
71502
+ 'const { createRequire } = require("node:module");',
71503
+ `const nodeRequire = createRequire(${target});`,
71504
+ `nodeRequire(${target});`,
71505
+ ""
71506
+ ].join("\n");
71507
+ }
71508
+ function buildSeaConfig(entryPath, blobPath) {
71509
+ return `${JSON.stringify(
71510
+ {
71511
+ main: entryPath,
71512
+ output: blobPath,
71513
+ disableExperimentalSEAWarning: true
71514
+ },
71515
+ null,
71516
+ 2
71517
+ )}
71518
+ `;
71519
+ }
71520
+ async function installWindowsNativeLauncher(options) {
71521
+ const nodeExe = options.nodeExe ?? process.execPath;
71522
+ if (!(0, import_node_fs16.existsSync)(options.cliPath)) {
71523
+ throw new Error(`cannot build okx-a2a.exe: CLI entry not found at ${options.cliPath}`);
71524
+ }
71525
+ if (!(0, import_node_fs16.existsSync)(nodeExe)) {
71526
+ throw new Error(`cannot build okx-a2a.exe: node executable not found at ${nodeExe}`);
71527
+ }
71528
+ const exePath = (0, import_node_path22.join)(options.targetDir, NATIVE_LAUNCHER_EXE_NAME);
71529
+ (0, import_node_fs16.mkdirSync)(options.targetDir, { recursive: true });
71530
+ const work = (0, import_node_fs16.mkdtempSync)((0, import_node_path22.join)((0, import_node_os7.tmpdir)(), "okx-a2a-sea-"));
71531
+ try {
71532
+ const entryPath = (0, import_node_path22.join)(work, "launcher-entry.js");
71533
+ const blobPath = (0, import_node_path22.join)(work, "okx-a2a.blob");
71534
+ const configPath = (0, import_node_path22.join)(work, "sea-config.json");
71535
+ (0, import_node_fs16.writeFileSync)(entryPath, buildLauncherEntryJs(options.cliPath), "utf8");
71536
+ (0, import_node_fs16.writeFileSync)(configPath, buildSeaConfig(entryPath, blobPath), "utf8");
71537
+ (0, import_node_child_process5.execFileSync)(nodeExe, ["--experimental-sea-config", configPath], {
71538
+ stdio: "ignore",
71539
+ windowsHide: true
71540
+ });
71541
+ (0, import_node_fs16.copyFileSync)(nodeExe, exePath);
71542
+ const isMac = process.platform === "darwin";
71543
+ if (isMac) {
71544
+ try {
71545
+ (0, import_node_child_process5.execFileSync)("codesign", ["--remove-signature", exePath], { stdio: "ignore" });
71546
+ } catch {
71547
+ }
71548
+ }
71549
+ injectSeaBlob(exePath, blobPath, isMac);
71550
+ if (isMac) {
71551
+ try {
71552
+ (0, import_node_child_process5.execFileSync)("codesign", ["--sign", "-", exePath], { stdio: "ignore" });
71553
+ } catch {
71554
+ }
71555
+ }
71556
+ logWinCompat(
71557
+ `${WIN_COMPAT_LOG_PREFIX} native launcher: built ${exePath} from node=${nodeExe} cli=${options.cliPath}`
71558
+ );
71559
+ return { exePath, cliPath: options.cliPath, nodeExe };
71560
+ } finally {
71561
+ (0, import_node_fs16.rmSync)(work, { recursive: true, force: true });
71562
+ }
71563
+ }
71564
+ function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2 = import_node_fs16.existsSync) {
71565
+ const dirs = pathValue.split(";").map((d) => d.trim()).filter(Boolean);
71566
+ if (appData) {
71567
+ dirs.push((0, import_node_path22.join)(appData, "npm"));
71568
+ }
71569
+ if (userProfile) {
71570
+ dirs.push((0, import_node_path22.join)(userProfile, ".local", "bin"));
71571
+ }
71572
+ for (const dir of dirs) {
71573
+ const candidate = (0, import_node_path22.join)(dir, NATIVE_LAUNCHER_EXE_NAME);
71574
+ if (fileExists2(candidate)) {
71575
+ return candidate;
71576
+ }
71577
+ }
71578
+ return null;
71579
+ }
71580
+ function resolveRunningCliPath() {
71581
+ const fromArgv = process.argv[1];
71582
+ if (fromArgv && /(?:^|[\\/])cli\.js$/.test(fromArgv) && (0, import_node_fs16.existsSync)(fromArgv)) {
71583
+ return fromArgv;
71584
+ }
71585
+ const beside = (0, import_node_path22.join)(__dirname, "cli.js");
71586
+ if ((0, import_node_fs16.existsSync)(beside)) {
71587
+ return beside;
71588
+ }
71589
+ if (fromArgv) {
71590
+ return fromArgv;
71591
+ }
71592
+ throw new Error("could not resolve the running okx-a2a CLI path for the native launcher");
71593
+ }
71594
+ async function ensureWindowsNativeLauncher(options = {}) {
71595
+ const platform = options.platform ?? process.platform;
71596
+ if (platform !== "win32") {
71597
+ return null;
71598
+ }
71599
+ const env = options.env ?? process.env;
71600
+ const existing = findWindowsNativeOkxA2aExe(env.PATH ?? env.Path ?? "", env.APPDATA, env.USERPROFILE);
71601
+ if (existing) {
71602
+ return { exePath: existing, installed: false };
71603
+ }
71604
+ const targetDir = env.APPDATA ? (0, import_node_path22.join)(env.APPDATA, "npm") : (0, import_node_path22.join)(env.USERPROFILE ?? (0, import_node_os7.homedir)(), ".local", "bin");
71605
+ const result = await installWindowsNativeLauncher({ cliPath: resolveRunningCliPath(), targetDir });
71606
+ return { exePath: result.exePath, installed: true };
71607
+ }
71608
+ var import_node_child_process5, import_node_fs16, import_node_module, import_node_os7, import_node_path22, SEA_SENTINEL_FUSE, NATIVE_LAUNCHER_EXE_NAME, POSTJECT_SPEC, POSTJECT_BIN;
71609
+ var init_win_native_launcher = __esm({
71610
+ "src/win-native-launcher.ts"() {
71611
+ "use strict";
71612
+ import_node_child_process5 = require("node:child_process");
71613
+ import_node_fs16 = require("node:fs");
71614
+ import_node_module = require("node:module");
71615
+ import_node_os7 = require("node:os");
71616
+ import_node_path22 = require("node:path");
71617
+ init_win_compat();
71618
+ init_win_spawn();
71619
+ SEA_SENTINEL_FUSE = "NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2";
71620
+ NATIVE_LAUNCHER_EXE_NAME = "okx-a2a.exe";
71621
+ POSTJECT_SPEC = "postject@1.0.0-alpha.6";
71622
+ POSTJECT_BIN = "postject";
71623
+ }
71624
+ });
71625
+
70896
71626
  // src/update-cli.ts
70897
71627
  var update_cli_exports = {};
70898
71628
  __export(update_cli_exports, {
@@ -70918,6 +71648,8 @@ __export(update_cli_exports, {
70918
71648
  parseUpdateArgs: () => parseUpdateArgs,
70919
71649
  printSetupUsage: () => printSetupUsage,
70920
71650
  printUpdateUsage: () => printUpdateUsage,
71651
+ resolveHermesConfigPath: () => resolveHermesConfigPath,
71652
+ resolveHermesPluginYamlPath: () => resolveHermesPluginYamlPath,
70921
71653
  runProviderLoginInteractive: () => runProviderLoginInteractive,
70922
71654
  setRedirectCommandStdoutToStderr: () => setRedirectCommandStdoutToStderr
70923
71655
  });
@@ -71131,6 +71863,7 @@ async function runSetup(options) {
71131
71863
  if (nodeChange.nodeChanged && provider) {
71132
71864
  await restartNodeDaemonAfterNodeSetup();
71133
71865
  }
71866
+ await ensureWindowsNativeLauncherForSetup();
71134
71867
  return {
71135
71868
  ok: true,
71136
71869
  state: "ready",
@@ -71164,6 +71897,7 @@ async function runSetup(options) {
71164
71897
  if (changes.pluginChanged) {
71165
71898
  await restartGatewayAfterSetup(resolvedTarget);
71166
71899
  }
71900
+ await ensureWindowsNativeLauncherForSetup();
71167
71901
  warnIfProviderMismatch(resolvedTarget);
71168
71902
  return {
71169
71903
  ok: true,
@@ -71610,7 +72344,7 @@ async function getCurrentNodeCliVersion() {
71610
72344
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
71611
72345
  }
71612
72346
  function getBundledNodeCliVersion() {
71613
- return true ? "0.1.4" : null;
72347
+ return true ? "0.1.6-beta-c3024b2b0b-260706164140" : null;
71614
72348
  }
71615
72349
  function readConfiguredAiProvider() {
71616
72350
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -71641,10 +72375,29 @@ async function restartNodeDaemonAfterUpdate() {
71641
72375
  }
71642
72376
  async function installNode(release, label) {
71643
72377
  const spec = buildNpmPackageSpec("node", release);
72378
+ if (process.platform === "win32") {
72379
+ const { getDaemonStatus: getDaemonStatus2, stopDaemon: stopDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
72380
+ const status = await getDaemonStatus2();
72381
+ if (status.running) {
72382
+ console.log(`[${label}] stopping the running daemon before reinstalling on Windows (its native addons lock the package dir)`);
72383
+ await stopDaemon2();
72384
+ }
72385
+ }
71644
72386
  console.log(`[${label}] installing ${spec}`);
71645
72387
  await runCommand("npm", ["install", "-g", spec]);
71646
72388
  console.log(`[${label}] okx-a2a node CLI ${label === "setup" ? "setup" : "update"} done`);
71647
72389
  }
72390
+ async function ensureWindowsNativeLauncherForSetup() {
72391
+ if (process.platform !== "win32") {
72392
+ return;
72393
+ }
72394
+ const { ensureWindowsNativeLauncher: ensureWindowsNativeLauncher2 } = await Promise.resolve().then(() => (init_win_native_launcher(), win_native_launcher_exports));
72395
+ const result = await ensureWindowsNativeLauncher2();
72396
+ if (!result) {
72397
+ return;
72398
+ }
72399
+ console.log(result.installed ? `[setup] built native okx-a2a.exe launcher at ${result.exePath}` : `[setup] native okx-a2a.exe launcher already present at ${result.exePath}`);
72400
+ }
71648
72401
  async function restartNodeDaemonAfterSetup(provider) {
71649
72402
  console.log(`[setup] restarting okx-a2a daemon after node CLI setup with provider=${provider}`);
71650
72403
  await runCommand("okx-a2a", ["daemon", "restart", "--provider", provider]);
@@ -71776,17 +72529,17 @@ async function updateHermes(release, options) {
71776
72529
  assertNotRunningInsideGateway("hermes");
71777
72530
  }
71778
72531
  const spec = buildNpmPackageSpec("hermes", release);
71779
- const workDir = await (0, import_promises7.mkdtemp)((0, import_node_path22.join)((0, import_node_os7.tmpdir)(), `okx-a2a-${label}-hermes-`));
72532
+ const workDir = await (0, import_promises7.mkdtemp)((0, import_node_path23.join)((0, import_node_os8.tmpdir)(), `okx-a2a-${label}-hermes-`));
71780
72533
  try {
71781
72534
  console.log(`[${label}] downloading ${spec}`);
71782
72535
  const npmTarball = await npmPack(spec, workDir);
71783
- const npmPackageDir = (0, import_node_path22.join)(workDir, "npm-package");
72536
+ const npmPackageDir = (0, import_node_path23.join)(workDir, "npm-package");
71784
72537
  await runCommand("tar", ["-xzf", npmTarball, "-C", npmPackageDir], { ensureDir: npmPackageDir });
71785
- const pluginTarball = await findHermesPluginTarball((0, import_node_path22.join)(npmPackageDir, "package", "dist"));
71786
- const pluginDir = (0, import_node_path22.join)(workDir, "plugin");
72538
+ const pluginTarball = await findHermesPluginTarball((0, import_node_path23.join)(npmPackageDir, "package", "dist"));
72539
+ const pluginDir = (0, import_node_path23.join)(workDir, "plugin");
71787
72540
  await runCommand("tar", ["-xzf", pluginTarball, "-C", pluginDir], { ensureDir: pluginDir });
71788
72541
  const unpackedPluginDir = await findFirstDirectory(pluginDir);
71789
- const installer = (0, import_node_path22.join)(unpackedPluginDir, "scripts", "install-or-upgrade.sh");
72542
+ const installer = (0, import_node_path23.join)(unpackedPluginDir, "scripts", "install-or-upgrade.sh");
71790
72543
  console.log(`[${label}] running ${installer}`);
71791
72544
  await runCommand("bash", [installer, ...options.restart ? ["--restart"] : []], { cwd: unpackedPluginDir });
71792
72545
  await normalizeHermesOkxA2aPluginConfig();
@@ -71801,7 +72554,7 @@ async function updateHermes(release, options) {
71801
72554
  }
71802
72555
  }
71803
72556
  async function installGatewayPluginForDoctor(target) {
71804
- const release = isPrereleaseVersion("0.1.4") ? "beta" : "latest";
72557
+ const release = isPrereleaseVersion("0.1.6-beta-c3024b2b0b-260706164140") ? "beta" : "latest";
71805
72558
  const insideTargetGateway = detectGatewayInvocation() === target;
71806
72559
  const options = {
71807
72560
  restart: !insideTargetGateway,
@@ -71852,7 +72605,7 @@ async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPa
71852
72605
  if (options.dryRun) {
71853
72606
  return true;
71854
72607
  }
71855
- await (0, import_promises7.mkdir)((0, import_node_path22.resolve)(configFile, ".."), { recursive: true });
72608
+ await (0, import_promises7.mkdir)((0, import_node_path23.resolve)(configFile, ".."), { recursive: true });
71856
72609
  await (0, import_promises7.writeFile)(configFile, "plugins:\n enabled:\n - okx-a2a\n");
71857
72610
  console.log(`[update] added Hermes plugins.enabled okx-a2a entry in ${configFile}`);
71858
72611
  return true;
@@ -72092,7 +72845,7 @@ function findFirstEnabledListItem(lines, startIndex, enabledIndent) {
72092
72845
  return null;
72093
72846
  }
72094
72847
  function resolveHermesConfigPath() {
72095
- return (0, import_node_path22.join)(process.env.HERMES_HOME ?? (0, import_node_path22.join)((0, import_node_os7.homedir)(), ".hermes"), "config.yaml");
72848
+ return (0, import_node_path23.join)(process.env.HERMES_HOME ?? (0, import_node_path23.join)((0, import_node_os8.homedir)(), ".hermes"), "config.yaml");
72096
72849
  }
72097
72850
  function lineIndent(line) {
72098
72851
  const match = line.match(/^\s*/);
@@ -72169,22 +72922,18 @@ async function assertGatewayPluginInstalled(target) {
72169
72922
  `okx-a2a ${target} plugin is not installed. Run \`okx-a2a setup ${target}\` first; use \`okx-a2a update ${target}\` only for an existing installation.`
72170
72923
  );
72171
72924
  }
72925
+ function resolveHermesPluginYamlPath() {
72926
+ return (0, import_node_path23.join)(process.env.HERMES_HOME ?? (0, import_node_path23.join)((0, import_node_os8.homedir)(), ".hermes"), "plugins", "platforms", "okx-a2a", "plugin.yaml");
72927
+ }
72172
72928
  async function isGatewayPluginInstalled(target) {
72173
72929
  if (target === "openclaw") {
72174
72930
  return (await getInstalledOpenClawPluginInfo()).installed;
72175
72931
  }
72176
- if ((0, import_node_fs16.existsSync)((0, import_node_path22.join)(process.env.HERMES_HOME ?? (0, import_node_path22.join)((0, import_node_os7.homedir)(), ".hermes"), "plugins", "platforms", "okx-a2a", "plugin.yaml"))) {
72177
- return true;
72178
- }
72179
- return await isGlobalNpmPackageInstalled(UPDATE_PACKAGES.hermes);
72180
- }
72181
- async function isGlobalNpmPackageInstalled(packageName) {
72182
- const result = await runCommandCaptureOptional("npm", ["list", "-g", packageName, "--depth=0"]);
72183
- return result.ok && result.stdout.includes(packageName);
72932
+ return (0, import_node_fs17.existsSync)(resolveHermesPluginYamlPath());
72184
72933
  }
72185
72934
  async function getInstalledGatewayPluginVersion(target) {
72186
72935
  if (target === "hermes") {
72187
- return await getInstalledHermesPluginVersion() ?? await getGlobalNpmPackageVersion(UPDATE_PACKAGES.hermes);
72936
+ return await getInstalledHermesPluginVersion();
72188
72937
  }
72189
72938
  return (await getInstalledOpenClawPluginInfo()).version;
72190
72939
  }
@@ -72267,7 +73016,7 @@ function parsePackageVersionFromText(output) {
72267
73016
  return output.match(/@okxweb3\/a2a-openclaw@([0-9A-Za-z.+-]+)/)?.[1] ?? null;
72268
73017
  }
72269
73018
  async function getInstalledHermesPluginVersion() {
72270
- const pluginYaml = (0, import_node_path22.join)(process.env.HERMES_HOME ?? (0, import_node_path22.join)((0, import_node_os7.homedir)(), ".hermes"), "plugins", "platforms", "okx-a2a", "plugin.yaml");
73019
+ const pluginYaml = (0, import_node_path23.join)(process.env.HERMES_HOME ?? (0, import_node_path23.join)((0, import_node_os8.homedir)(), ".hermes"), "plugins", "platforms", "okx-a2a", "plugin.yaml");
72271
73020
  try {
72272
73021
  const content3 = await (0, import_promises7.readFile)(pluginYaml, "utf8");
72273
73022
  return parsePluginYamlVersion(content3);
@@ -72325,7 +73074,7 @@ async function npmPack(spec, destination) {
72325
73074
  if (!tarballName) {
72326
73075
  throw new Error(`Unable to detect npm pack tarball from output: ${output.trim()}`);
72327
73076
  }
72328
- return (0, import_node_path22.resolve)(destination, (0, import_node_path22.basename)(tarballName));
73077
+ return (0, import_node_path23.resolve)(destination, (0, import_node_path23.basename)(tarballName));
72329
73078
  }
72330
73079
  async function findHermesPluginTarball(distDir) {
72331
73080
  const entries = await (0, import_promises7.readdir)(distDir);
@@ -72333,7 +73082,7 @@ async function findHermesPluginTarball(distDir) {
72333
73082
  if (!tarball) {
72334
73083
  throw new Error(`Hermes npm package did not contain dist/okx-a2a-hermes-plugin-*.tar.gz`);
72335
73084
  }
72336
- return (0, import_node_path22.join)(distDir, tarball);
73085
+ return (0, import_node_path23.join)(distDir, tarball);
72337
73086
  }
72338
73087
  async function findFirstDirectory(parent) {
72339
73088
  const entries = await (0, import_promises7.readdir)(parent, { withFileTypes: true });
@@ -72341,7 +73090,7 @@ async function findFirstDirectory(parent) {
72341
73090
  if (!dir) {
72342
73091
  throw new Error(`No unpacked plugin directory found under ${parent}`);
72343
73092
  }
72344
- return (0, import_node_path22.join)(parent, dir.name);
73093
+ return (0, import_node_path23.join)(parent, dir.name);
72345
73094
  }
72346
73095
  function readOption(args, name2) {
72347
73096
  const index2 = args.indexOf(name2);
@@ -72392,7 +73141,7 @@ async function runCommand(command, args, options = {}) {
72392
73141
  await new Promise((resolvePromise, reject) => {
72393
73142
  const invocation = buildExternalCommandInvocation(command, args);
72394
73143
  const redirect = redirectCommandStdoutToStderr || options.redirectStdoutToStderr === true;
72395
- const child = (0, import_node_child_process5.spawn)(invocation.command, invocation.args, {
73144
+ const child = (0, import_node_child_process6.spawn)(invocation.command, invocation.args, {
72396
73145
  cwd: options.cwd,
72397
73146
  stdio: redirect ? [options.inheritStdin ? "inherit" : "ignore", "pipe", "pipe"] : "inherit",
72398
73147
  windowsVerbatimArguments: invocation.windowsVerbatimArguments
@@ -72436,7 +73185,7 @@ async function runCommand(command, args, options = {}) {
72436
73185
  async function runCommandCapture(command, args) {
72437
73186
  return await new Promise((resolvePromise, reject) => {
72438
73187
  const invocation = buildExternalCommandInvocation(command, args);
72439
- const child = (0, import_node_child_process5.spawn)(invocation.command, invocation.args, {
73188
+ const child = (0, import_node_child_process6.spawn)(invocation.command, invocation.args, {
72440
73189
  stdio: ["ignore", "pipe", "pipe"],
72441
73190
  windowsVerbatimArguments: invocation.windowsVerbatimArguments
72442
73191
  });
@@ -72469,7 +73218,7 @@ ${stderr}`));
72469
73218
  async function runCommandCaptureOptional(command, args) {
72470
73219
  return await new Promise((resolvePromise) => {
72471
73220
  const invocation = buildExternalCommandInvocation(command, args);
72472
- const child = (0, import_node_child_process5.spawn)(invocation.command, invocation.args, {
73221
+ const child = (0, import_node_child_process6.spawn)(invocation.command, invocation.args, {
72473
73222
  stdio: ["ignore", "pipe", "ignore"],
72474
73223
  windowsVerbatimArguments: invocation.windowsVerbatimArguments
72475
73224
  });
@@ -72489,7 +73238,7 @@ async function runCommandCaptureOptional(command, args) {
72489
73238
  async function runCommandCaptureStatus(command, args) {
72490
73239
  return await new Promise((resolvePromise) => {
72491
73240
  const invocation = buildExternalCommandInvocation(command, args);
72492
- const child = (0, import_node_child_process5.spawn)(invocation.command, invocation.args, {
73241
+ const child = (0, import_node_child_process6.spawn)(invocation.command, invocation.args, {
72493
73242
  stdio: ["ignore", "pipe", "pipe"],
72494
73243
  windowsVerbatimArguments: invocation.windowsVerbatimArguments
72495
73244
  });
@@ -72531,15 +73280,15 @@ function buildExternalCommandInvocation(command, args, platform = process.platfo
72531
73280
  function formatExternalCommand(command, args) {
72532
73281
  return [command, ...args].join(" ");
72533
73282
  }
72534
- var import_node_child_process5, import_node_fs16, import_promises7, import_node_os7, import_node_path22, UPDATE_PACKAGES, CODEX_NPM_PACKAGE, OPENCLAW_FORCE_INSTALL_FLAG, OPENCLAW_UNSAFE_INSTALL_FLAG, OKX_A2A_PLUGIN_ID, OPENCLAW_SESSION_DM_SCOPE_CONFIG_PATH, OPENCLAW_SESSION_DM_SCOPE_CONFIG_VALUE, OPENCLAW_PLUGIN_ALLOW_CONFIG_PATH, OPENCLAW_OKX_A2A_CONVERSATION_HOOK_ACCESS_CONFIG_PATH, DEFAULT_AI_PROVIDER_LOGIN_TIMEOUT_MS, SetupBlockedError, redirectCommandStdoutToStderr;
73283
+ var import_node_child_process6, import_node_fs17, import_promises7, import_node_os8, import_node_path23, UPDATE_PACKAGES, CODEX_NPM_PACKAGE, OPENCLAW_FORCE_INSTALL_FLAG, OPENCLAW_UNSAFE_INSTALL_FLAG, OKX_A2A_PLUGIN_ID, OPENCLAW_SESSION_DM_SCOPE_CONFIG_PATH, OPENCLAW_SESSION_DM_SCOPE_CONFIG_VALUE, OPENCLAW_PLUGIN_ALLOW_CONFIG_PATH, OPENCLAW_OKX_A2A_CONVERSATION_HOOK_ACCESS_CONFIG_PATH, DEFAULT_AI_PROVIDER_LOGIN_TIMEOUT_MS, SetupBlockedError, redirectCommandStdoutToStderr;
72535
73284
  var init_update_cli = __esm({
72536
73285
  "src/update-cli.ts"() {
72537
73286
  "use strict";
72538
- import_node_child_process5 = require("node:child_process");
72539
- import_node_fs16 = require("node:fs");
73287
+ import_node_child_process6 = require("node:child_process");
73288
+ import_node_fs17 = require("node:fs");
72540
73289
  import_promises7 = require("node:fs/promises");
72541
- import_node_os7 = require("node:os");
72542
- import_node_path22 = require("node:path");
73290
+ import_node_os8 = require("node:os");
73291
+ import_node_path23 = require("node:path");
72543
73292
  init_ai_command();
72544
73293
  init_win_spawn();
72545
73294
  init_ai_provider();
@@ -72570,160 +73319,6 @@ var init_update_cli = __esm({
72570
73319
  }
72571
73320
  });
72572
73321
 
72573
- // src/win-native-launcher.ts
72574
- var win_native_launcher_exports = {};
72575
- __export(win_native_launcher_exports, {
72576
- NATIVE_LAUNCHER_EXE_NAME: () => NATIVE_LAUNCHER_EXE_NAME,
72577
- buildLauncherEntryJs: () => buildLauncherEntryJs,
72578
- buildSeaConfig: () => buildSeaConfig,
72579
- installWindowsNativeLauncher: () => installWindowsNativeLauncher
72580
- });
72581
- function isPostjectRunnable() {
72582
- try {
72583
- const probe = spawnSyncCompat(POSTJECT_BIN, ["--help"], {
72584
- stdio: "ignore",
72585
- windowsHide: true,
72586
- timeout: 3e4
72587
- });
72588
- return probe.status === 0;
72589
- } catch {
72590
- return false;
72591
- }
72592
- }
72593
- function resolvePostjectCommand() {
72594
- try {
72595
- const cliPath = (0, import_node_module.createRequire)(__filename).resolve("postject/dist/cli.js");
72596
- if ((0, import_node_fs20.existsSync)(cliPath)) {
72597
- return { command: process.execPath, prefixArgs: [cliPath] };
72598
- }
72599
- } catch {
72600
- }
72601
- if (!isPostjectRunnable()) {
72602
- logWinCompat(`${WIN_COMPAT_LOG_PREFIX} native launcher: installing ${POSTJECT_SPEC} globally`);
72603
- const install = spawnSyncCompat("npm", [
72604
- "install",
72605
- "-g",
72606
- POSTJECT_SPEC,
72607
- "--no-audit",
72608
- "--no-fund",
72609
- "--loglevel=error"
72610
- ], { encoding: "utf8", windowsHide: true, timeout: 18e4 });
72611
- if (install.status !== 0 || !isPostjectRunnable()) {
72612
- throw new Error(
72613
- `failed to install ${POSTJECT_SPEC} (needed to build okx-a2a.exe): ${String(install.stderr || install.error?.message || "unknown error").slice(0, 300)}`
72614
- );
72615
- }
72616
- }
72617
- return { command: POSTJECT_BIN, prefixArgs: [] };
72618
- }
72619
- function injectSeaBlob(exePath, blobPath, isMac) {
72620
- const { command, prefixArgs: prefixArgs2 } = resolvePostjectCommand();
72621
- const args = [
72622
- ...prefixArgs2,
72623
- exePath,
72624
- "NODE_SEA_BLOB",
72625
- blobPath,
72626
- "--sentinel-fuse",
72627
- SEA_SENTINEL_FUSE,
72628
- "--overwrite"
72629
- ];
72630
- if (isMac) {
72631
- args.push("--macho-segment-name", "NODE_SEA");
72632
- }
72633
- const result = spawnSyncCompat(command, args, {
72634
- encoding: "utf8",
72635
- windowsHide: true,
72636
- timeout: 12e4
72637
- });
72638
- if (result.status !== 0) {
72639
- throw new Error(
72640
- `postject injection failed: ${String(result.stderr || result.error?.message || `exit ${result.status}`).slice(0, 300)}`
72641
- );
72642
- }
72643
- }
72644
- function buildLauncherEntryJs(cliPath) {
72645
- const target = JSON.stringify(cliPath);
72646
- return [
72647
- 'const { createRequire } = require("node:module");',
72648
- `const nodeRequire = createRequire(${target});`,
72649
- `nodeRequire(${target});`,
72650
- ""
72651
- ].join("\n");
72652
- }
72653
- function buildSeaConfig(entryPath, blobPath) {
72654
- return `${JSON.stringify(
72655
- {
72656
- main: entryPath,
72657
- output: blobPath,
72658
- disableExperimentalSEAWarning: true
72659
- },
72660
- null,
72661
- 2
72662
- )}
72663
- `;
72664
- }
72665
- async function installWindowsNativeLauncher(options) {
72666
- const nodeExe = options.nodeExe ?? process.execPath;
72667
- if (!(0, import_node_fs20.existsSync)(options.cliPath)) {
72668
- throw new Error(`cannot build okx-a2a.exe: CLI entry not found at ${options.cliPath}`);
72669
- }
72670
- if (!(0, import_node_fs20.existsSync)(nodeExe)) {
72671
- throw new Error(`cannot build okx-a2a.exe: node executable not found at ${nodeExe}`);
72672
- }
72673
- const exePath = (0, import_node_path25.join)(options.targetDir, NATIVE_LAUNCHER_EXE_NAME);
72674
- (0, import_node_fs20.mkdirSync)(options.targetDir, { recursive: true });
72675
- const work = (0, import_node_fs20.mkdtempSync)((0, import_node_path25.join)((0, import_node_os9.tmpdir)(), "okx-a2a-sea-"));
72676
- try {
72677
- const entryPath = (0, import_node_path25.join)(work, "launcher-entry.js");
72678
- const blobPath = (0, import_node_path25.join)(work, "okx-a2a.blob");
72679
- const configPath = (0, import_node_path25.join)(work, "sea-config.json");
72680
- (0, import_node_fs20.writeFileSync)(entryPath, buildLauncherEntryJs(options.cliPath), "utf8");
72681
- (0, import_node_fs20.writeFileSync)(configPath, buildSeaConfig(entryPath, blobPath), "utf8");
72682
- (0, import_node_child_process8.execFileSync)(nodeExe, ["--experimental-sea-config", configPath], {
72683
- stdio: "ignore",
72684
- windowsHide: true
72685
- });
72686
- (0, import_node_fs20.copyFileSync)(nodeExe, exePath);
72687
- const isMac = process.platform === "darwin";
72688
- if (isMac) {
72689
- try {
72690
- (0, import_node_child_process8.execFileSync)("codesign", ["--remove-signature", exePath], { stdio: "ignore" });
72691
- } catch {
72692
- }
72693
- }
72694
- injectSeaBlob(exePath, blobPath, isMac);
72695
- if (isMac) {
72696
- try {
72697
- (0, import_node_child_process8.execFileSync)("codesign", ["--sign", "-", exePath], { stdio: "ignore" });
72698
- } catch {
72699
- }
72700
- }
72701
- logWinCompat(
72702
- `${WIN_COMPAT_LOG_PREFIX} native launcher: built ${exePath} from node=${nodeExe} cli=${options.cliPath}`
72703
- );
72704
- return { exePath, cliPath: options.cliPath, nodeExe };
72705
- } finally {
72706
- (0, import_node_fs20.rmSync)(work, { recursive: true, force: true });
72707
- }
72708
- }
72709
- var import_node_child_process8, import_node_fs20, import_node_module, import_node_os9, import_node_path25, SEA_SENTINEL_FUSE, NATIVE_LAUNCHER_EXE_NAME, POSTJECT_SPEC, POSTJECT_BIN;
72710
- var init_win_native_launcher = __esm({
72711
- "src/win-native-launcher.ts"() {
72712
- "use strict";
72713
- import_node_child_process8 = require("node:child_process");
72714
- import_node_fs20 = require("node:fs");
72715
- import_node_module = require("node:module");
72716
- import_node_os9 = require("node:os");
72717
- import_node_path25 = require("node:path");
72718
- init_win_compat();
72719
- init_win_spawn();
72720
- SEA_SENTINEL_FUSE = "NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2";
72721
- NATIVE_LAUNCHER_EXE_NAME = "okx-a2a.exe";
72722
- POSTJECT_SPEC = "postject@1.0.0-alpha.6";
72723
- POSTJECT_BIN = "postject";
72724
- }
72725
- });
72726
-
72727
73322
  // src/index.ts
72728
73323
  var index_exports = {};
72729
73324
  __export(index_exports, {
@@ -72798,12 +73393,14 @@ __export(index_exports, {
72798
73393
  ensureDaemonReady: () => ensureDaemonReady,
72799
73394
  ensureDefaultAiProvider: () => ensureDefaultAiProvider,
72800
73395
  ensureOpenClawOkxA2aPluginConfig: () => ensureOpenClawOkxA2aPluginConfig,
73396
+ ensureWindowsNativeLauncher: () => ensureWindowsNativeLauncher,
72801
73397
  extractAiSessionId: () => extractAiSessionId,
72802
73398
  extractXmtpSentAtMs: () => extractXmtpSentAtMs2,
72803
73399
  findWindowsNativeOkxA2aExe: () => findWindowsNativeOkxA2aExe,
72804
73400
  followFile: () => followFile,
72805
73401
  formatDoctorReportForHumans: () => formatDoctorReportForHumans,
72806
73402
  getDaemonStatus: () => getDaemonStatus,
73403
+ getHermesGatewayPluginStatus: () => getHermesGatewayPluginStatus,
72807
73404
  handleDoctorCommand: () => handleDoctorCommand,
72808
73405
  handleXmtpSendCommand: () => handleXmtpSendCommand,
72809
73406
  hasAiRuntimeMarker: () => hasAiRuntimeMarker,
@@ -72882,502 +73479,7 @@ __export(index_exports, {
72882
73479
  writeAiPermissionPresetToConfig: () => writeAiPermissionPresetToConfig
72883
73480
  });
72884
73481
  module.exports = __toCommonJS(index_exports);
72885
-
72886
- // src/daemon.ts
72887
- var import_node_fs3 = require("node:fs");
72888
- var import_promises2 = require("node:fs/promises");
72889
- var import_node_child_process = require("node:child_process");
72890
- var import_node_path5 = require("node:path");
72891
- init_paths();
72892
- init_session_store();
72893
-
72894
- // src/daemon-lock.ts
72895
- var import_promises = require("node:fs/promises");
72896
- var import_node_path4 = require("node:path");
72897
- init_paths();
72898
- init_a2a_paths();
72899
- var OWNER_FILE = "owner.json";
72900
- var EMPTY_LOCK_STALE_MS = 1e4;
72901
- var DAEMON_CAPABILITY_AI_DISPATCH = "ai-dispatch";
72902
- var DAEMON_CAPABILITIES = [
72903
- DAEMON_CAPABILITY_AI_DISPATCH
72904
- ];
72905
- function isProcessAlive(pid) {
72906
- try {
72907
- process.kill(pid, 0);
72908
- return true;
72909
- } catch (err2) {
72910
- return err2.code === "EPERM";
72911
- }
72912
- }
72913
- function ownerPath(lockPath) {
72914
- return (0, import_node_path4.join)(lockPath, OWNER_FILE);
72915
- }
72916
- async function readDaemonLock(lockPath) {
72917
- let metadata = null;
72918
- try {
72919
- const raw = await (0, import_promises.readFile)(ownerPath(lockPath), "utf8");
72920
- metadata = JSON.parse(raw);
72921
- } catch (err2) {
72922
- const code2 = err2.code;
72923
- if (code2 === "ENOENT") {
72924
- try {
72925
- const info = await (0, import_promises.stat)(lockPath);
72926
- const stale = Date.now() - info.mtimeMs > EMPTY_LOCK_STALE_MS;
72927
- return { metadata: null, running: !stale, stale, path: lockPath };
72928
- } catch (statErr) {
72929
- const statCode = statErr.code;
72930
- if (statCode === "ENOENT") {
72931
- return { metadata: null, running: false, stale: false, path: lockPath };
72932
- }
72933
- throw statErr;
72934
- }
72935
- }
72936
- if (err2 instanceof SyntaxError) {
72937
- return { metadata: null, running: false, stale: true, path: lockPath };
72938
- }
72939
- throw err2;
72940
- }
72941
- const running = Number.isInteger(metadata.pid) && metadata.pid > 0 && isProcessAlive(metadata.pid);
72942
- return { metadata, running, stale: !running, path: lockPath };
72943
- }
72944
- async function markDaemonReady(lockPath) {
72945
- const current = await readDaemonLock(lockPath);
72946
- const metadata = current.metadata;
72947
- if (!metadata || metadata.pid !== process.pid) {
72948
- return;
72949
- }
72950
- await (0, import_promises.writeFile)(ownerPath(lockPath), `${JSON.stringify({
72951
- ...metadata,
72952
- ready: true,
72953
- readyAt: (/* @__PURE__ */ new Date()).toISOString()
72954
- }, null, 2)}
72955
- `, "utf8");
72956
- }
72957
- async function removeLock(lockPath) {
72958
- await (0, import_promises.rm)(lockPath, { recursive: true, force: true });
72959
- }
72960
- async function acquireDaemonLock(paths, entry) {
72961
- const metadata = {
72962
- pid: process.pid,
72963
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
72964
- cwd: process.cwd(),
72965
- entry,
72966
- homeDir: paths.homeDir,
72967
- capabilities: DAEMON_CAPABILITIES,
72968
- ready: false
72969
- };
72970
- ensureTaskDir(paths.runDir);
72971
- for (let attempt = 0; attempt < 2; attempt += 1) {
72972
- try {
72973
- await (0, import_promises.mkdir)(paths.daemonLockPath, { mode: A2A_TASK_DIR_MODE });
72974
- await chmodBestEffort(paths.daemonLockPath, A2A_TASK_DIR_MODE);
72975
- await (0, import_promises.writeFile)(ownerPath(paths.daemonLockPath), `${JSON.stringify(metadata, null, 2)}
72976
- `, "utf8");
72977
- return {
72978
- metadata,
72979
- release: async () => {
72980
- const current = await readDaemonLock(paths.daemonLockPath);
72981
- if (current.metadata?.pid === process.pid) {
72982
- await removeLock(paths.daemonLockPath);
72983
- }
72984
- }
72985
- };
72986
- } catch (err2) {
72987
- const code2 = err2.code;
72988
- if (code2 !== "EEXIST") {
72989
- throw err2;
72990
- }
72991
- const current = await readDaemonLock(paths.daemonLockPath);
72992
- if (current.running) {
72993
- return null;
72994
- }
72995
- if (!current.stale) {
72996
- return null;
72997
- }
72998
- await removeLock(paths.daemonLockPath);
72999
- }
73000
- }
73001
- return null;
73002
- }
73003
- async function chmodBestEffort(path, mode) {
73004
- try {
73005
- await (0, import_promises.chmod)(path, mode);
73006
- } catch (err2) {
73007
- const code2 = err2.code;
73008
- if (code2 !== "EPERM" && code2 !== "EACCES") {
73009
- throw err2;
73010
- }
73011
- }
73012
- }
73013
-
73014
- // src/daemon.ts
73015
- var STOP_GRACE_MS = 5e3;
73016
- var FORCE_KILL_GRACE_MS = 5e3;
73017
- var START_EXIT_CHECK_MS = 750;
73018
- var DEFAULT_READY_TIMEOUT_MS = 12e4;
73019
- var READY_POLL_MS = 250;
73020
- var DAEMON_READY_TIMEOUT_ENV = "OKX_A2A_DAEMON_READY_TIMEOUT_MS";
73021
- async function readPid(pidPath) {
73022
- try {
73023
- const raw = await (0, import_promises2.readFile)(pidPath, "utf8");
73024
- const pid = Number.parseInt(raw.trim(), 10);
73025
- return Number.isInteger(pid) && pid > 0 ? pid : null;
73026
- } catch (err2) {
73027
- const code2 = err2.code;
73028
- if (code2 === "ENOENT") {
73029
- return null;
73030
- }
73031
- throw err2;
73032
- }
73033
- }
73034
- async function removePid(pidPath) {
73035
- try {
73036
- await (0, import_promises2.unlink)(pidPath);
73037
- } catch (err2) {
73038
- const code2 = err2.code;
73039
- if (code2 !== "ENOENT") {
73040
- throw err2;
73041
- }
73042
- }
73043
- }
73044
- async function ensureDaemonDirs(homeDir) {
73045
- const paths = resolveTaskPaths(homeDir);
73046
- ensureTaskDir(paths.jobsDir);
73047
- ensureTaskDir(paths.runDir);
73048
- ensureTaskDir(paths.logsDir);
73049
- ensureTaskDir(paths.commandsDir);
73050
- ensureTaskDir(paths.downloadsDir);
73051
- ensureTaskDir(paths.xmtpDir);
73052
- ensureTaskDir(paths.sqliteDir);
73053
- return paths;
73054
- }
73055
- async function ensureAiWorkspace(paths) {
73056
- const aiWorkingDir = paths.workspaceDir;
73057
- await (0, import_promises2.rm)(aiWorkingDir, { recursive: true, force: true });
73058
- ensureTaskDir(aiWorkingDir);
73059
- return aiWorkingDir;
73060
- }
73061
- async function waitForImmediateExit(child, timeoutMs) {
73062
- return await new Promise((resolve6) => {
73063
- let timer;
73064
- const onExit = () => {
73065
- clearTimeout(timer);
73066
- resolve6(true);
73067
- };
73068
- timer = setTimeout(() => {
73069
- child.off("exit", onExit);
73070
- resolve6(false);
73071
- }, timeoutMs);
73072
- child.once("exit", onExit);
73073
- });
73074
- }
73075
- async function getDaemonStatus(homeDir) {
73076
- const paths = resolveTaskPaths(homeDir);
73077
- const pid = await readPid(paths.pidPath);
73078
- const lock = await readDaemonLock(paths.daemonLockPath);
73079
- const lockPid = lock.metadata?.pid ?? null;
73080
- const lockReadyStateKnown = !!lock.metadata && (typeof lock.metadata.ready === "boolean" || typeof lock.metadata.readyAt === "string");
73081
- const lockReady = lockReadyStateKnown ? lock.metadata?.ready === true || typeof lock.metadata?.readyAt === "string" : true;
73082
- if (lock.running) {
73083
- return {
73084
- running: true,
73085
- pid: lockPid ?? pid,
73086
- stale: false,
73087
- capabilities: lock.metadata?.capabilities ?? [],
73088
- ready: lockReady,
73089
- readyAt: lock.metadata?.readyAt ?? null,
73090
- readyStateKnown: lockReadyStateKnown,
73091
- pidPath: paths.pidPath,
73092
- lockPath: paths.daemonLockPath,
73093
- lockPid,
73094
- lockStale: false
73095
- };
73096
- }
73097
- if (!pid) {
73098
- return {
73099
- running: false,
73100
- pid: null,
73101
- stale: lock.stale,
73102
- capabilities: [],
73103
- ready: false,
73104
- readyAt: null,
73105
- readyStateKnown: false,
73106
- pidPath: paths.pidPath,
73107
- lockPath: paths.daemonLockPath,
73108
- lockPid,
73109
- lockStale: lock.stale
73110
- };
73111
- }
73112
- const running = isProcessAlive(pid);
73113
- return {
73114
- running,
73115
- pid,
73116
- stale: !running || lock.stale,
73117
- capabilities: running ? lock.metadata?.capabilities ?? [] : [],
73118
- ready: running && !lockReadyStateKnown ? true : running && lockReady,
73119
- readyAt: running ? lock.metadata?.readyAt ?? null : null,
73120
- readyStateKnown: running && lockReadyStateKnown,
73121
- pidPath: paths.pidPath,
73122
- lockPath: paths.daemonLockPath,
73123
- lockPid,
73124
- lockStale: lock.stale
73125
- };
73126
- }
73127
- async function startDaemon(homeDir) {
73128
- const paths = await ensureDaemonDirs(homeDir);
73129
- const aiWorkingDir = await ensureAiWorkspace(paths);
73130
- const current = await getDaemonStatus(homeDir);
73131
- if (current.running) {
73132
- return {
73133
- ...current,
73134
- started: false,
73135
- logPath: paths.listenerLogPath
73136
- };
73137
- }
73138
- if (current.stale) {
73139
- await removePid(paths.pidPath);
73140
- }
73141
- const store = new SessionStore({ homeDir });
73142
- try {
73143
- store.setSetting("ai_working_dir", aiWorkingDir);
73144
- store.resetGlobalSession(SYSTEM_NOTIFICATION_SESSION_KEY);
73145
- } finally {
73146
- store.close();
73147
- }
73148
- const logFd = (0, import_node_fs3.openSync)(paths.listenerLogPath, "a");
73149
- const entry = process.env.OKX_AGENT_TASK_CLI_PATH || (0, import_node_path5.join)(__dirname, "cli.js");
73150
- const daemonCwd = (0, import_node_path5.join)(__dirname, "..");
73151
- const child = (0, import_node_child_process.spawn)(process.execPath, [entry, "run"], {
73152
- cwd: daemonCwd,
73153
- detached: true,
73154
- // win32: keep the detached daemon from flashing/holding a console window.
73155
- // Ignored on every non-win32 platform.
73156
- windowsHide: true,
73157
- env: {
73158
- ...process.env,
73159
- OKX_AGENT_TASK_HOME: paths.homeDir,
73160
- OKX_AGENT_TASK_DAEMON: "1",
73161
- OKX_A2A_AI_CWD: aiWorkingDir,
73162
- OKX_AGENT_TASK_AI_CWD: aiWorkingDir
73163
- },
73164
- stdio: ["ignore", logFd, logFd]
73165
- });
73166
- (0, import_node_fs3.closeSync)(logFd);
73167
- child.unref();
73168
- await (0, import_promises2.writeFile)(paths.pidPath, `${child.pid ?? ""}
73169
- `, "utf8");
73170
- if (await waitForImmediateExit(child, START_EXIT_CHECK_MS)) {
73171
- const status = await getDaemonStatus(homeDir);
73172
- if (status.running && status.lockPid) {
73173
- await (0, import_promises2.writeFile)(paths.pidPath, `${status.lockPid}
73174
- `, "utf8");
73175
- } else {
73176
- await removePid(paths.pidPath);
73177
- }
73178
- return {
73179
- ...status,
73180
- started: false,
73181
- logPath: paths.listenerLogPath
73182
- };
73183
- }
73184
- return {
73185
- running: true,
73186
- pid: child.pid ?? null,
73187
- stale: false,
73188
- capabilities: DAEMON_CAPABILITIES,
73189
- ready: false,
73190
- readyAt: null,
73191
- readyStateKnown: true,
73192
- pidPath: paths.pidPath,
73193
- lockPath: paths.daemonLockPath,
73194
- lockPid: child.pid ?? null,
73195
- lockStale: false,
73196
- started: true,
73197
- logPath: paths.listenerLogPath
73198
- };
73199
- }
73200
- async function waitForExit(pid, timeoutMs) {
73201
- const deadline = Date.now() + timeoutMs;
73202
- while (Date.now() < deadline) {
73203
- if (!isProcessAlive(pid)) {
73204
- return true;
73205
- }
73206
- await new Promise((resolve6) => setTimeout(resolve6, 100));
73207
- }
73208
- return !isProcessAlive(pid);
73209
- }
73210
- function signalProcess(pid, signal) {
73211
- try {
73212
- process.kill(pid, signal);
73213
- return true;
73214
- } catch (err2) {
73215
- const code2 = err2.code;
73216
- if (code2 === "ESRCH") {
73217
- return false;
73218
- }
73219
- throw err2;
73220
- }
73221
- }
73222
- async function stopDaemon(homeDir) {
73223
- const paths = resolveTaskPaths(homeDir);
73224
- const current = await getDaemonStatus(homeDir);
73225
- if (!current.pid) {
73226
- return { ...current, stopped: false };
73227
- }
73228
- if (!current.running) {
73229
- await removePid(paths.pidPath);
73230
- return {
73231
- running: false,
73232
- pid: current.pid,
73233
- stale: false,
73234
- capabilities: [],
73235
- ready: false,
73236
- readyAt: null,
73237
- readyStateKnown: false,
73238
- pidPath: paths.pidPath,
73239
- lockPath: paths.daemonLockPath,
73240
- lockPid: current.lockPid,
73241
- lockStale: current.lockStale,
73242
- stopped: false
73243
- };
73244
- }
73245
- const signalled = signalProcess(current.pid, "SIGTERM");
73246
- let forced = false;
73247
- let exited = !signalled || await waitForExit(current.pid, STOP_GRACE_MS);
73248
- if (!exited) {
73249
- forced = true;
73250
- const killed = signalProcess(current.pid, "SIGKILL");
73251
- exited = !killed || await waitForExit(current.pid, FORCE_KILL_GRACE_MS);
73252
- }
73253
- if (exited) {
73254
- await removePid(paths.pidPath);
73255
- }
73256
- return {
73257
- running: !exited,
73258
- pid: current.pid,
73259
- stale: false,
73260
- capabilities: exited ? [] : current.capabilities,
73261
- ready: !exited && current.ready,
73262
- readyAt: !exited ? current.readyAt : null,
73263
- readyStateKnown: !exited && current.readyStateKnown,
73264
- pidPath: paths.pidPath,
73265
- lockPath: paths.daemonLockPath,
73266
- lockPid: current.lockPid,
73267
- lockStale: current.lockStale,
73268
- stopped: exited,
73269
- forced
73270
- };
73271
- }
73272
- async function ensureDaemonReady(options = {}) {
73273
- const paths = resolveTaskPaths(options.homeDir);
73274
- const commandName = options.commandName ?? "command";
73275
- const timeoutMs = options.timeoutMs ?? readReadyTimeoutMs(options.env ?? process.env);
73276
- let status = await getDaemonStatus(options.homeDir);
73277
- let started = false;
73278
- let logPath = paths.listenerLogPath;
73279
- if (!status.running) {
73280
- options.stderr?.write(`[okx-a2a] ${commandName} requires the daemon; starting daemon...
73281
- `);
73282
- const startResult = await startDaemon(options.homeDir);
73283
- started = startResult.started;
73284
- logPath = startResult.logPath;
73285
- status = startResult;
73286
- if (!status.running) {
73287
- throw new Error(
73288
- `${commandName} requires the daemon, but automatic daemon start failed. Check ${logPath} or run \`okx-a2a daemon restart\`.`
73289
- );
73290
- }
73291
- status = await waitForDaemonReady({
73292
- homeDir: options.homeDir,
73293
- timeoutMs,
73294
- requiredCapabilities: options.requiredCapabilities,
73295
- requireKnownReadyState: true,
73296
- logPath,
73297
- commandName
73298
- });
73299
- options.stderr?.write(`[okx-a2a] daemon ready pid=${status.pid ?? "(unknown)"} log=${logPath}
73300
- `);
73301
- } else if (status.readyStateKnown && !status.ready) {
73302
- status = await waitForDaemonReady({
73303
- homeDir: options.homeDir,
73304
- timeoutMs,
73305
- requiredCapabilities: options.requiredCapabilities,
73306
- requireKnownReadyState: false,
73307
- logPath,
73308
- commandName
73309
- });
73310
- }
73311
- assertRequiredCapabilities(status, options.requiredCapabilities, commandName);
73312
- return {
73313
- ...status,
73314
- started,
73315
- logPath
73316
- };
73317
- }
73318
- async function waitForDaemonReady(options) {
73319
- const deadline = Date.now() + Math.max(0, options.timeoutMs);
73320
- let lastStatus = await getDaemonStatus(options.homeDir);
73321
- while (Date.now() <= deadline) {
73322
- const status = await getDaemonStatus(options.homeDir);
73323
- lastStatus = status;
73324
- if (!status.running) {
73325
- if (status.stale) {
73326
- throw new Error(
73327
- `${options.commandName} requires the daemon, but the daemon exited before becoming ready. Check ${options.logPath} or run \`okx-a2a daemon restart\`.`
73328
- );
73329
- }
73330
- } else if (isReadyForCommand(status, options.requiredCapabilities, options.requireKnownReadyState)) {
73331
- return status;
73332
- } else if (status.ready && findMissingCapabilities(status, options.requiredCapabilities).length > 0) {
73333
- assertRequiredCapabilities(status, options.requiredCapabilities, options.commandName);
73334
- }
73335
- await sleep(Math.min(READY_POLL_MS, Math.max(1, deadline - Date.now() + 1)));
73336
- }
73337
- const missing = findMissingCapabilities(lastStatus, options.requiredCapabilities);
73338
- const capabilitySuffix = missing.length > 0 ? ` missingCapabilities=${missing.join(",")}` : "";
73339
- throw new Error(
73340
- `${options.commandName} requires the daemon, but it did not become ready within ${options.timeoutMs}ms${capabilitySuffix}. Check ${options.logPath} or run \`okx-a2a daemon restart\`.`
73341
- );
73342
- }
73343
- function isReadyForCommand(status, requiredCapabilities, requireKnownReadyState = false) {
73344
- if (!status.running) {
73345
- return false;
73346
- }
73347
- if (requireKnownReadyState && !status.readyStateKnown) {
73348
- return false;
73349
- }
73350
- if (status.readyStateKnown && !status.ready) {
73351
- return false;
73352
- }
73353
- return findMissingCapabilities(status, requiredCapabilities).length === 0;
73354
- }
73355
- function assertRequiredCapabilities(status, requiredCapabilities, commandName) {
73356
- const missing = findMissingCapabilities(status, requiredCapabilities);
73357
- if (missing.length === 0) {
73358
- return;
73359
- }
73360
- throw new Error(
73361
- `${commandName} requires a daemon with ${missing.join(",")} support. Run \`okx-a2a daemon restart\` first.`
73362
- );
73363
- }
73364
- function findMissingCapabilities(status, requiredCapabilities) {
73365
- if (!requiredCapabilities || requiredCapabilities.length === 0) {
73366
- return [];
73367
- }
73368
- return requiredCapabilities.filter((capability) => !status.capabilities.includes(capability));
73369
- }
73370
- function readReadyTimeoutMs(env) {
73371
- const raw = env[DAEMON_READY_TIMEOUT_ENV]?.trim();
73372
- if (!raw) {
73373
- return DEFAULT_READY_TIMEOUT_MS;
73374
- }
73375
- const parsed = Number(raw);
73376
- return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_READY_TIMEOUT_MS;
73377
- }
73378
- function sleep(ms) {
73379
- return new Promise((resolve6) => setTimeout(resolve6, ms));
73380
- }
73482
+ init_daemon();
73381
73483
 
73382
73484
  // src/ai-runner.ts
73383
73485
  init_log();
@@ -73864,6 +73966,7 @@ var LogEvent = {
73864
73966
  ONCHAINOS_CLI_ERROR: "Onchainos CLI error",
73865
73967
  HEARTBEAT_FAILED: "Heartbeat failed",
73866
73968
  HEARTBEAT_SKIPPED: "Heartbeat skipped",
73969
+ HEARTBEAT_GATEWAY_CHECK_FAILED: "Heartbeat gateway check failed",
73867
73970
  MESSAGE_PARSE_FAILED: "Message parse failed",
73868
73971
  MESSAGE_HANDLER_ERROR: "Message handler error",
73869
73972
  OFFLINE_REPLAY_FAILED: "Offline replay failed",
@@ -86127,10 +86230,6 @@ function compareTimestamp(a, b) {
86127
86230
  }
86128
86231
 
86129
86232
  // ../core/src/xmtp-sdk/onchainos/agent-status.ts
86130
- var XMTP_COMMUNICABLE_AGENT_STATUSES = /* @__PURE__ */ new Set([
86131
- 1 /* ACTIVE */,
86132
- 2 /* USER_OFFLINE */
86133
- ]);
86134
86233
  var XMTP_BLOCKED_AGENT_STATUSES = /* @__PURE__ */ new Set([
86135
86234
  3 /* SECURITY_BLACKLISTED */,
86136
86235
  4 /* RISK_BLACKLISTED */,
@@ -86140,7 +86239,7 @@ function isAgentXmtpCommunicable(agent) {
86140
86239
  if (!agent) {
86141
86240
  return false;
86142
86241
  }
86143
- return XMTP_COMMUNICABLE_AGENT_STATUSES.has(Number(agent.status));
86242
+ return true;
86144
86243
  }
86145
86244
  function isAgentXmtpBlocked(agent) {
86146
86245
  if (!agent) {
@@ -89305,7 +89404,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
89305
89404
  client: {
89306
89405
  id: "gateway-client",
89307
89406
  displayName: "okx-a2a-node",
89308
- version: "0.1.4",
89407
+ version: "0.1.6-beta-c3024b2b0b-260706164140",
89309
89408
  platform: "node",
89310
89409
  mode: "backend",
89311
89410
  instanceId
@@ -89316,7 +89415,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
89316
89415
  commands: [],
89317
89416
  permissions: {},
89318
89417
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
89319
- userAgent: `okx-a2a-node/${"0.1.4"}`,
89418
+ userAgent: `okx-a2a-node/${"0.1.6-beta-c3024b2b0b-260706164140"}`,
89320
89419
  auth: {
89321
89420
  ...config.token ? { token: config.token } : {},
89322
89421
  ...config.password ? { password: config.password } : {}
@@ -93780,13 +93879,14 @@ function userWatchEventDeliveredSentryExtra(event) {
93780
93879
  }
93781
93880
 
93782
93881
  // src/listener.ts
93882
+ init_daemon_lock();
93783
93883
  init_ai_provider();
93784
93884
 
93785
93885
  // ../core/src/sentry-config.ts
93786
93886
  var environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
93787
93887
  var SENTRY_CONFIG = {
93788
93888
  projectName: "okx/openclaw-okx-a2a-extension",
93789
- release: "0.1.4",
93889
+ release: "0.1.6-beta-c3024b2b0b-260706164140",
93790
93890
  environment
93791
93891
  };
93792
93892
 
@@ -93826,20 +93926,31 @@ async function isGatewayAvailableForHeartbeat(options) {
93826
93926
  }
93827
93927
  return isHermesGatewayPluginEnabled({ env: options.env });
93828
93928
  }
93829
- async function isHermesGatewayPluginEnabled(options = {}) {
93929
+ async function getHermesGatewayPluginStatus(options = {}) {
93830
93930
  const env = options.env ?? process.env;
93831
- if (options.requireGatewayRuntime && detectGatewayInvocation(env) !== "hermes") {
93832
- return false;
93833
- }
93834
93931
  const hermesHome = env.HERMES_HOME?.trim() || (0, import_node_path21.join)((0, import_node_os6.homedir)(), ".hermes");
93835
- if (!(0, import_node_fs15.existsSync)((0, import_node_path21.join)(hermesHome, "plugins", "platforms", "okx-a2a", "plugin.yaml"))) {
93836
- return false;
93932
+ const pluginYamlPath = (0, import_node_path21.join)(hermesHome, "plugins", "platforms", "okx-a2a", "plugin.yaml");
93933
+ if (!(0, import_node_fs15.existsSync)(pluginYamlPath)) {
93934
+ return { enabled: false, reason: "plugin_yaml_missing", hermesHome, checkedPath: pluginYamlPath };
93837
93935
  }
93936
+ const configPath = (0, import_node_path21.join)(hermesHome, "config.yaml");
93937
+ let content3;
93838
93938
  try {
93839
- return hermesConfigEnablesOkxA2a(await (0, import_promises6.readFile)((0, import_node_path21.join)(hermesHome, "config.yaml"), "utf8"));
93939
+ content3 = await (0, import_promises6.readFile)(configPath, "utf8");
93840
93940
  } catch {
93941
+ return { enabled: false, reason: "config_read_error", hermesHome, checkedPath: configPath };
93942
+ }
93943
+ if (!hermesConfigEnablesOkxA2a(content3)) {
93944
+ return { enabled: false, reason: "config_disabled", hermesHome, checkedPath: configPath };
93945
+ }
93946
+ return { enabled: true, hermesHome, checkedPath: pluginYamlPath };
93947
+ }
93948
+ async function isHermesGatewayPluginEnabled(options = {}) {
93949
+ const env = options.env ?? process.env;
93950
+ if (options.requireGatewayRuntime && detectGatewayInvocation(env) !== "hermes") {
93841
93951
  return false;
93842
93952
  }
93953
+ return (await getHermesGatewayPluginStatus({ env })).enabled;
93843
93954
  }
93844
93955
  function hermesConfigEnablesOkxA2a(content3) {
93845
93956
  let inPlugins = false;
@@ -94013,12 +94124,12 @@ async function runListenerWithLock(options, paths) {
94013
94124
  }));
94014
94125
  }
94015
94126
  });
94016
- service.setPluginVersion("0.1.4");
94127
+ service.setPluginVersion("0.1.6-beta-c3024b2b0b-260706164140");
94017
94128
  await service.init();
94018
94129
  const pluginVersionStatus = service.pluginVersionStatus;
94019
94130
  if (pluginVersionStatus.unavailable) {
94020
94131
  throw new Error(
94021
- `@okxweb3/a2a-node v${"0.1.4"} is below the required minimum v${pluginVersionStatus.minVersion}`
94132
+ `@okxweb3/a2a-node v${"0.1.6-beta-c3024b2b0b-260706164140"} is below the required minimum v${pluginVersionStatus.minVersion}`
94022
94133
  );
94023
94134
  }
94024
94135
  const systemConfig = service.getSystemConfig();
@@ -94036,7 +94147,7 @@ async function runListenerWithLock(options, paths) {
94036
94147
  onchainosAgentId: "*",
94037
94148
  reason: "system-config missing sentryDsn",
94038
94149
  pluginId: "@okxweb3/a2a-node",
94039
- pluginVersion: "0.1.4"
94150
+ pluginVersion: "0.1.6-beta-c3024b2b0b-260706164140"
94040
94151
  });
94041
94152
  }
94042
94153
  logWithTimestamp(
@@ -94076,7 +94187,28 @@ async function runListenerWithLock(options, paths) {
94076
94187
  const hasActiveAgents = service.getClients().size > 0;
94077
94188
  let shouldHeartbeat = hasActiveAgents;
94078
94189
  const heartbeatProvider = resolveConfiguredAiProvider({ store: sessionStore }) ?? detectGatewayInvocation();
94079
- if (hasActiveAgents) {
94190
+ if (hasActiveAgents && heartbeatProvider === "hermes") {
94191
+ const hermesStatus = await getHermesGatewayPluginStatus();
94192
+ if (!hermesStatus.enabled) {
94193
+ logWithTimestamp(
94194
+ `[okx-agent-task] provider=hermes gateway check failed (${hermesStatus.reason}), sending heartbeat anyway`
94195
+ );
94196
+ logger.error(
94197
+ LogEvent.HEARTBEAT_GATEWAY_CHECK_FAILED,
94198
+ new Error(`heartbeat gateway check failed: provider=hermes reason=${hermesStatus.reason}`),
94199
+ {
94200
+ component: "node_listener",
94201
+ stage: "sync_tick",
94202
+ reason: hermesStatus.reason ?? "unknown",
94203
+ provider: "hermes",
94204
+ hermesHome: hermesStatus.hermesHome,
94205
+ checkedPath: hermesStatus.checkedPath,
94206
+ chainIndex: ONCHAINOS_CHAIN_INDEX,
94207
+ communicationClass: "gateway_or_plugin"
94208
+ }
94209
+ );
94210
+ }
94211
+ } else if (hasActiveAgents) {
94080
94212
  const gatewayAvailable = await isGatewayAvailableForHeartbeat({
94081
94213
  provider: heartbeatProvider
94082
94214
  });
@@ -94398,7 +94530,7 @@ init_update_cli();
94398
94530
  init_win_spawn();
94399
94531
 
94400
94532
  // src/log-tail.ts
94401
- var import_node_fs17 = require("node:fs");
94533
+ var import_node_fs18 = require("node:fs");
94402
94534
  var import_promises8 = require("node:fs/promises");
94403
94535
  var import_node_string_decoder = require("node:string_decoder");
94404
94536
  init_win_spawn();
@@ -94522,7 +94654,7 @@ async function followFile(filePath, onData, options = {}) {
94522
94654
  void check();
94523
94655
  }, pollIntervalMs);
94524
94656
  try {
94525
- watcher = (0, import_node_fs17.watch)(filePath, () => {
94657
+ watcher = (0, import_node_fs18.watch)(filePath, () => {
94526
94658
  void check();
94527
94659
  });
94528
94660
  watcher.on("error", (error) => {
@@ -94588,8 +94720,6 @@ init_ai_provider();
94588
94720
  init_update_cli();
94589
94721
 
94590
94722
  // src/doctor-cli.ts
94591
- var import_node_fs21 = require("node:fs");
94592
- var import_node_os10 = require("node:os");
94593
94723
  var import_node_path26 = require("node:path");
94594
94724
  init_log();
94595
94725
  init_win_compat();
@@ -94597,18 +94727,18 @@ init_ai_command();
94597
94727
  init_ai_provider();
94598
94728
 
94599
94729
  // src/autostart.ts
94600
- var import_node_child_process7 = require("node:child_process");
94601
- var import_node_fs19 = require("node:fs");
94730
+ var import_node_child_process8 = require("node:child_process");
94731
+ var import_node_fs20 = require("node:fs");
94602
94732
  var import_promises10 = require("node:fs/promises");
94603
- var import_node_os8 = require("node:os");
94604
- var import_node_path24 = require("node:path");
94733
+ var import_node_os9 = require("node:os");
94734
+ var import_node_path25 = require("node:path");
94605
94735
  var import_node_util2 = require("node:util");
94606
94736
 
94607
94737
  // src/autostart-windows.ts
94608
- var import_node_child_process6 = require("node:child_process");
94609
- var import_node_fs18 = require("node:fs");
94738
+ var import_node_child_process7 = require("node:child_process");
94739
+ var import_node_fs19 = require("node:fs");
94610
94740
  var import_promises9 = require("node:fs/promises");
94611
- var import_node_path23 = require("node:path");
94741
+ var import_node_path24 = require("node:path");
94612
94742
  init_log();
94613
94743
  init_paths();
94614
94744
  init_win_spawn();
@@ -94619,10 +94749,10 @@ var SCHTASKS_TIMEOUT_MS = 15e3;
94619
94749
  var LOG_SNIPPET_LIMIT = 500;
94620
94750
  function resolveWindowsAutostartPaths(homeDir) {
94621
94751
  const resolvedHome = homeDir ?? resolveTaskPaths().homeDir;
94622
- const autostartDir = (0, import_node_path23.join)(resolvedHome, "autostart");
94752
+ const autostartDir = (0, import_node_path24.join)(resolvedHome, "autostart");
94623
94753
  return {
94624
94754
  autostartDir,
94625
- vbsPath: (0, import_node_path23.join)(autostartDir, VBS_FILE_NAME)
94755
+ vbsPath: (0, import_node_path24.join)(autostartDir, VBS_FILE_NAME)
94626
94756
  };
94627
94757
  }
94628
94758
  function escapeVbsString(value) {
@@ -94654,7 +94784,7 @@ function buildAutostartVbs(options) {
94654
94784
  `;
94655
94785
  }
94656
94786
  function isWindowsElevated() {
94657
- const result = (0, import_node_child_process6.spawnSync)("net", ["session"], {
94787
+ const result = (0, import_node_child_process7.spawnSync)("net", ["session"], {
94658
94788
  windowsHide: true,
94659
94789
  encoding: "utf8",
94660
94790
  timeout: 5e3,
@@ -94699,10 +94829,10 @@ function resolveWindowsCliPath() {
94699
94829
  logWinCompat(`${WIN_COMPAT_LOG_PREFIX} autostart: process.argv[1] is empty, cannot resolve okx-a2a CLI path`);
94700
94830
  throw new Error("Unable to resolve current okx-a2a CLI path");
94701
94831
  }
94702
- return (0, import_node_path23.resolve)(entry);
94832
+ return (0, import_node_path24.resolve)(entry);
94703
94833
  }
94704
94834
  function runSchtasks(operation, args) {
94705
- const result = (0, import_node_child_process6.spawnSync)(SCHTASKS_BIN, args, {
94835
+ const result = (0, import_node_child_process7.spawnSync)(SCHTASKS_BIN, args, {
94706
94836
  windowsHide: true,
94707
94837
  encoding: "utf8",
94708
94838
  timeout: SCHTASKS_TIMEOUT_MS
@@ -94740,10 +94870,10 @@ async function installWindowsAutostart() {
94740
94870
  const execPath = process.execPath;
94741
94871
  const cliPath = resolveWindowsCliPath();
94742
94872
  const pathValue = process.env.PATH?.trim() || "";
94743
- if (!(0, import_node_fs18.existsSync)(execPath)) {
94873
+ if (!(0, import_node_fs19.existsSync)(execPath)) {
94744
94874
  throw new Error(`autostart: node executable not found at ${execPath}`);
94745
94875
  }
94746
- if (!(0, import_node_fs18.existsSync)(cliPath)) {
94876
+ if (!(0, import_node_fs19.existsSync)(cliPath)) {
94747
94877
  throw new Error(`autostart: okx-a2a CLI entry not found at ${cliPath}`);
94748
94878
  }
94749
94879
  await (0, import_promises9.mkdir)(paths.autostartDir, { recursive: true });
@@ -94778,22 +94908,22 @@ function isWindowsAutostartInstalled() {
94778
94908
 
94779
94909
  // src/autostart.ts
94780
94910
  init_paths();
94781
- var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process7.execFile);
94911
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process8.execFile);
94782
94912
  var SERVICE_NAME = "okx-a2a.service";
94783
94913
  var LAUNCHD_LABEL = "com.okx.a2a";
94784
94914
  var LAUNCHD_PLIST_NAME = `${LAUNCHD_LABEL}.plist`;
94785
- function resolveSystemdAutostartPaths(home = (0, import_node_os8.homedir)()) {
94786
- const serviceDir = (0, import_node_path24.join)(home, ".config", "systemd", "user");
94915
+ function resolveSystemdAutostartPaths(home = (0, import_node_os9.homedir)()) {
94916
+ const serviceDir = (0, import_node_path25.join)(home, ".config", "systemd", "user");
94787
94917
  return {
94788
94918
  serviceDir,
94789
- servicePath: (0, import_node_path24.join)(serviceDir, SERVICE_NAME)
94919
+ servicePath: (0, import_node_path25.join)(serviceDir, SERVICE_NAME)
94790
94920
  };
94791
94921
  }
94792
- function resolveLaunchdAutostartPaths(home = (0, import_node_os8.homedir)()) {
94793
- const agentDir = (0, import_node_path24.join)(home, "Library", "LaunchAgents");
94922
+ function resolveLaunchdAutostartPaths(home = (0, import_node_os9.homedir)()) {
94923
+ const agentDir = (0, import_node_path25.join)(home, "Library", "LaunchAgents");
94794
94924
  return {
94795
94925
  agentDir,
94796
- plistPath: (0, import_node_path24.join)(agentDir, LAUNCHD_PLIST_NAME)
94926
+ plistPath: (0, import_node_path25.join)(agentDir, LAUNCHD_PLIST_NAME)
94797
94927
  };
94798
94928
  }
94799
94929
  function quoteSystemdArg(value) {
@@ -94807,7 +94937,7 @@ function resolveCliPath() {
94807
94937
  if (!entry) {
94808
94938
  throw new Error("Unable to resolve current okx-a2a CLI path");
94809
94939
  }
94810
- return (0, import_node_path24.resolve)(entry);
94940
+ return (0, import_node_path25.resolve)(entry);
94811
94941
  }
94812
94942
  function buildSystemdUserService() {
94813
94943
  const taskHome2 = resolveTaskHome();
@@ -94942,10 +95072,10 @@ async function installAutostart() {
94942
95072
  }
94943
95073
  function isAutostartInstalled() {
94944
95074
  if (process.platform === "linux") {
94945
- return (0, import_node_fs19.existsSync)(resolveSystemdAutostartPaths().servicePath);
95075
+ return (0, import_node_fs20.existsSync)(resolveSystemdAutostartPaths().servicePath);
94946
95076
  }
94947
95077
  if (process.platform === "darwin") {
94948
- return (0, import_node_fs19.existsSync)(resolveLaunchdAutostartPaths().plistPath);
95078
+ return (0, import_node_fs20.existsSync)(resolveLaunchdAutostartPaths().plistPath);
94949
95079
  }
94950
95080
  if (process.platform === "win32") {
94951
95081
  return isWindowsAutostartInstalled();
@@ -94953,7 +95083,11 @@ function isAutostartInstalled() {
94953
95083
  return false;
94954
95084
  }
94955
95085
 
95086
+ // src/doctor-cli.ts
95087
+ init_daemon();
95088
+
94956
95089
  // src/daemon-ops.ts
95090
+ init_daemon();
94957
95091
  async function refreshAgentsAndWait(timeoutMs = 6e4) {
94958
95092
  const status = await getDaemonStatus();
94959
95093
  if (!status.running) {
@@ -95010,7 +95144,9 @@ async function dispatchRuntimeSwitchUserMessage(store, result) {
95010
95144
  // src/doctor-cli.ts
95011
95145
  init_session_store();
95012
95146
  init_update_cli();
95147
+ init_win_native_launcher();
95013
95148
  init_win_spawn();
95149
+ init_win_native_launcher();
95014
95150
  var DOCTOR_MIN_NODE_VERSION = "22.14.0";
95015
95151
  var DOCTOR_DAEMON_READY_TIMEOUT_MS = 2e4;
95016
95152
  var NODE_PACKAGE_SPEC = "@okxweb3/a2a-node";
@@ -95220,22 +95356,6 @@ var cliVersionChecker = {
95220
95356
  return `npm install completed; installed version could not be verified from npm metadata (was ${before}) \u2014 daemon will be restarted to be safe`;
95221
95357
  }
95222
95358
  };
95223
- function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2 = import_node_fs21.existsSync) {
95224
- const dirs = pathValue.split(";").map((d) => d.trim()).filter(Boolean);
95225
- if (appData) {
95226
- dirs.push((0, import_node_path26.join)(appData, "npm"));
95227
- }
95228
- if (userProfile) {
95229
- dirs.push((0, import_node_path26.join)(userProfile, ".local", "bin"));
95230
- }
95231
- for (const dir of dirs) {
95232
- const candidate = (0, import_node_path26.join)(dir, "okx-a2a.exe");
95233
- if (fileExists2(candidate)) {
95234
- return candidate;
95235
- }
95236
- }
95237
- return null;
95238
- }
95239
95359
  var windowsNativeLauncherChecker = {
95240
95360
  id: "windows_native_launcher",
95241
95361
  title: "Windows native launcher (okx-a2a.exe)",
@@ -95272,27 +95392,13 @@ var windowsNativeLauncherChecker = {
95272
95392
  };
95273
95393
  },
95274
95394
  applyFix: async (ctx) => {
95275
- const targetDir = ctx.env.APPDATA ? (0, import_node_path26.join)(ctx.env.APPDATA, "npm") : (0, import_node_path26.join)(ctx.env.USERPROFILE ?? (0, import_node_os10.homedir)(), ".local", "bin");
95276
- const cliPath = resolveRunningCliPath();
95277
- const { installWindowsNativeLauncher: installWindowsNativeLauncher2 } = await Promise.resolve().then(() => (init_win_native_launcher(), win_native_launcher_exports));
95278
- const result = await installWindowsNativeLauncher2({ cliPath, targetDir });
95279
- return `built native launcher ${result.exePath} (SEA over ${result.nodeExe}, entry ${result.cliPath})`;
95395
+ const result = await ensureWindowsNativeLauncher({ env: ctx.env, platform: "win32" });
95396
+ if (!result) {
95397
+ throw new Error("native launcher fix is only applicable on Windows");
95398
+ }
95399
+ return result.installed ? `built native launcher ${result.exePath} (SEA over your node.exe)` : `native launcher already present at ${result.exePath}`;
95280
95400
  }
95281
95401
  };
95282
- function resolveRunningCliPath() {
95283
- const fromArgv = process.argv[1];
95284
- if (fromArgv && /(?:^|[\\/])cli\.js$/.test(fromArgv) && (0, import_node_fs21.existsSync)(fromArgv)) {
95285
- return fromArgv;
95286
- }
95287
- const beside = (0, import_node_path26.join)(__dirname, "cli.js");
95288
- if ((0, import_node_fs21.existsSync)(beside)) {
95289
- return beside;
95290
- }
95291
- if (fromArgv) {
95292
- return fromArgv;
95293
- }
95294
- throw new Error("could not resolve the running okx-a2a CLI path for the native launcher");
95295
- }
95296
95402
  var providerBindingChecker = {
95297
95403
  id: "provider_binding",
95298
95404
  title: "Default AI provider binding",
@@ -95312,13 +95418,18 @@ var providerBindingChecker = {
95312
95418
  data: { bound, detectedRuntime: runtime }
95313
95419
  };
95314
95420
  }
95421
+ const autoFixCanSucceed = !!expected;
95315
95422
  return {
95316
95423
  id: "provider_binding",
95317
95424
  title: "Default AI provider binding",
95318
95425
  status: "fail",
95319
95426
  severity: "required",
95320
95427
  detail: bound ? `default provider ${bound} does not match the detected runtime ${runtime}` : "no default AI provider is bound",
95321
- fix: { kind: "auto", description: "Run the in-memory runtime switch (equivalent of `okx-a2a switch-runtime`)." },
95428
+ fix: autoFixCanSucceed ? { kind: "auto", description: "Run the in-memory runtime switch (equivalent of `okx-a2a switch-runtime`)." } : {
95429
+ kind: "manual",
95430
+ description: "No AI runtime detected and no default provider is bound. Run doctor from your AI environment (OpenClaw / Codex / Claude / Hermes), or bind one manually first.",
95431
+ command: "okx-a2a ai-provider set --provider <codex|claude|hermes|openclaw>"
95432
+ },
95322
95433
  data: { bound, detectedRuntime: runtime }
95323
95434
  };
95324
95435
  } finally {
@@ -95330,7 +95441,7 @@ var providerBindingChecker = {
95330
95441
  try {
95331
95442
  const result = await performRuntimeSwitch(store);
95332
95443
  if (!result.ok) {
95333
- throw new Error(result.message || "runtime switch failed");
95444
+ throw new Error(result.userMessage || result.message || "runtime switch failed");
95334
95445
  }
95335
95446
  return `runtime switch: provider=${result.provider} ${result.changed ? "(switched)" : "(already current)"}`;
95336
95447
  } finally {
@@ -95391,7 +95502,14 @@ var providerCliChecker = {
95391
95502
  status: "fail",
95392
95503
  severity: "required",
95393
95504
  detail: `${provider} CLI at ${resolved} is not logged in (${auth.reason})`,
95394
- fix: {
95505
+ // Logging in needs a human (device/browser auth). In --non-interactive
95506
+ // mode never launch it — degrade to a manual instruction so unattended
95507
+ // callers (install scripts) cannot hang waiting on stdin.
95508
+ fix: ctx.nonInteractive ? {
95509
+ kind: "manual",
95510
+ description: "Log in with the command below, then re-run okx-a2a doctor.",
95511
+ command: loginCommand
95512
+ } : {
95395
95513
  kind: "auto",
95396
95514
  description: "--fix launches the interactive login flow (same as setup: device/browser auth, waits for completion). You can also log in yourself with the command below, then re-run okx-a2a doctor.",
95397
95515
  command: loginCommand
@@ -95430,6 +95548,11 @@ var providerCliChecker = {
95430
95548
  }
95431
95549
  const auth = provider === "codex" ? await checkCodexCliAuthStatus(resolved) : await checkClaudeCliAuthStatus(resolved);
95432
95550
  if (!auth.ok) {
95551
+ if (ctx.nonInteractive) {
95552
+ throw new Error(
95553
+ `${provider} CLI is installed but not logged in; non-interactive mode skips the login flow \u2014 log in yourself and re-run okx-a2a doctor`
95554
+ );
95555
+ }
95433
95556
  errorWithTimestamp(`[doctor] launching ${provider} CLI login (interactive; waiting for completion)`);
95434
95557
  const login = await runProviderLoginInteractive(provider, resolved);
95435
95558
  if (!login.ok) {
@@ -95453,13 +95576,14 @@ var gatewayPluginChecker = {
95453
95576
  return null;
95454
95577
  }
95455
95578
  const installed = await isGatewayPluginInstalled(ctx.target);
95579
+ const hermesPathSuffix = ctx.target === "hermes" ? ` (checked ${resolveHermesPluginYamlPath()})` : "";
95456
95580
  if (installed) {
95457
95581
  return {
95458
95582
  id: "gateway_plugin",
95459
95583
  title: "Gateway plugin installed",
95460
95584
  status: "pass",
95461
95585
  severity: "required",
95462
- detail: `${ctx.target} okx-a2a plugin is installed`
95586
+ detail: `${ctx.target} okx-a2a plugin is installed${hermesPathSuffix}`
95463
95587
  };
95464
95588
  }
95465
95589
  const hermesOnWindows = ctx.target === "hermes" && ctx.platform === "win32";
@@ -95468,7 +95592,7 @@ var gatewayPluginChecker = {
95468
95592
  title: "Gateway plugin installed",
95469
95593
  status: "fail",
95470
95594
  severity: "required",
95471
- detail: `${ctx.target} okx-a2a plugin is not installed`,
95595
+ detail: `${ctx.target} okx-a2a plugin is not installed${hermesPathSuffix}`,
95472
95596
  fix: hermesOnWindows ? {
95473
95597
  kind: "manual",
95474
95598
  description: "Hermes plugin installation requires bash and is not supported on Windows. Use WSL or run setup on macOS/Linux."
@@ -95497,13 +95621,14 @@ var gatewayConfigChecker = {
95497
95621
  return null;
95498
95622
  }
95499
95623
  const drift = ctx.target === "openclaw" ? await ensureOpenClawOkxA2aPluginConfig({ dryRun: true }) : await ensureHermesOkxA2aPluginConfig(void 0, { dryRun: true });
95624
+ const hermesPathSuffix = ctx.target === "hermes" ? ` (checked ${resolveHermesConfigPath()})` : "";
95500
95625
  if (!drift) {
95501
95626
  return {
95502
95627
  id: "gateway_config",
95503
95628
  title: "Gateway plugin config",
95504
95629
  status: "pass",
95505
95630
  severity: "required",
95506
- detail: `${ctx.target} okx-a2a plugin config is normalized`
95631
+ detail: `${ctx.target} okx-a2a plugin config is normalized${hermesPathSuffix}`
95507
95632
  };
95508
95633
  }
95509
95634
  return {
@@ -95511,7 +95636,7 @@ var gatewayConfigChecker = {
95511
95636
  title: "Gateway plugin config",
95512
95637
  status: "fail",
95513
95638
  severity: "required",
95514
- detail: `${ctx.target} okx-a2a plugin config needs normalization`,
95639
+ detail: `${ctx.target} okx-a2a plugin config needs normalization${hermesPathSuffix}`,
95515
95640
  fix: { kind: "auto", description: `Apply the ${ctx.target} config normalization in-process.` }
95516
95641
  };
95517
95642
  },
@@ -95759,8 +95884,9 @@ async function runDoctor(options = {}) {
95759
95884
  platform: options.platform ?? process.platform,
95760
95885
  env: options.env ?? process.env,
95761
95886
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
95762
- cliVersion: options.cliVersion ?? (true ? "0.1.4" : "0.0.0"),
95887
+ cliVersion: options.cliVersion ?? (true ? "0.1.6-beta-c3024b2b0b-260706164140" : "0.0.0"),
95763
95888
  fixMode: options.fix === true,
95889
+ nonInteractive: options.nonInteractive === true,
95764
95890
  packageChanged: false
95765
95891
  };
95766
95892
  const checkers = options.checkers ?? CHECKERS;
@@ -95907,6 +96033,7 @@ function formatDoctorReportForHumans(report) {
95907
96033
  async function handleDoctorCommand(args) {
95908
96034
  const json = args.includes("--json");
95909
96035
  const fix = args.includes("--fix");
96036
+ const nonInteractive = args.includes("--non-interactive");
95910
96037
  const targetIndex = args.indexOf("--target");
95911
96038
  const rawTarget = targetIndex >= 0 ? args[targetIndex + 1] : void 0;
95912
96039
  if (targetIndex >= 0 && (rawTarget === void 0 || rawTarget.startsWith("--"))) {
@@ -95930,7 +96057,7 @@ async function handleDoctorCommand(args) {
95930
96057
  };
95931
96058
  let report;
95932
96059
  try {
95933
- report = await runDoctor({ fix, ...rawTarget ? { target: rawTarget } : {} });
96060
+ report = await runDoctor({ fix, nonInteractive, ...rawTarget ? { target: rawTarget } : {} });
95934
96061
  } catch (error) {
95935
96062
  restoreStdout();
95936
96063
  const message = error instanceof Error ? error.message : String(error);
@@ -96036,12 +96163,14 @@ init_win_native_launcher();
96036
96163
  ensureDaemonReady,
96037
96164
  ensureDefaultAiProvider,
96038
96165
  ensureOpenClawOkxA2aPluginConfig,
96166
+ ensureWindowsNativeLauncher,
96039
96167
  extractAiSessionId,
96040
96168
  extractXmtpSentAtMs,
96041
96169
  findWindowsNativeOkxA2aExe,
96042
96170
  followFile,
96043
96171
  formatDoctorReportForHumans,
96044
96172
  getDaemonStatus,
96173
+ getHermesGatewayPluginStatus,
96045
96174
  handleDoctorCommand,
96046
96175
  handleXmtpSendCommand,
96047
96176
  hasAiRuntimeMarker,