0agent 1.0.11 → 1.0.12

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 (2) hide show
  1. package/dist/daemon.mjs +912 -505
  2. package/package.json +1 -1
package/dist/daemon.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // packages/daemon/src/ZeroAgentDaemon.ts
2
- import { writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "node:fs";
3
- import { resolve as resolve4 } from "node:path";
2
+ import { writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "node:fs";
3
+ import { resolve as resolve5 } from "node:path";
4
4
  import { homedir as homedir3 } from "node:os";
5
5
 
6
6
  // packages/core/src/graph/GraphNode.ts
@@ -1686,429 +1686,535 @@ var EntityScopedContextLoader = class {
1686
1686
  };
1687
1687
 
1688
1688
  // packages/daemon/src/AgentExecutor.ts
1689
- import { spawn } from "node:child_process";
1690
- import { writeFileSync, readFileSync as readFileSync2, readdirSync, mkdirSync, existsSync as existsSync2 } from "node:fs";
1691
- import { resolve as resolve2, dirname, relative } from "node:path";
1689
+ import { spawn as spawn2 } from "node:child_process";
1690
+ import { writeFileSync as writeFileSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, mkdirSync as mkdirSync2, existsSync as existsSync3 } from "node:fs";
1691
+ import { resolve as resolve3, dirname as dirname2, relative } from "node:path";
1692
1692
 
1693
- // packages/daemon/src/LLMExecutor.ts
1694
- var AGENT_TOOLS = [
1695
- {
1696
- name: "shell_exec",
1697
- description: "Execute a shell command in the working directory. Use for running servers (with & for background), installing packages, running tests, git operations, etc. Returns stdout + stderr.",
1693
+ // packages/daemon/src/capabilities/WebSearchCapability.ts
1694
+ import { execSync, spawnSync } from "node:child_process";
1695
+ var WebSearchCapability = class {
1696
+ name = "web_search";
1697
+ description = "Search the web. Returns titles, URLs, and snippets. No API key needed.";
1698
+ toolDefinition = {
1699
+ name: "web_search",
1700
+ description: "Search the web and return titles, URLs, and snippets. No API key needed. Use first to find pages, then scrape_url for full content.",
1698
1701
  input_schema: {
1699
1702
  type: "object",
1700
1703
  properties: {
1701
- command: { type: "string", description: "Shell command to execute" },
1702
- timeout_ms: { type: "number", description: "Timeout in milliseconds (default 30000)" }
1704
+ query: { type: "string", description: "Search query" },
1705
+ num_results: { type: "number", description: "Number of results (default 5, max 10)" }
1703
1706
  },
1704
- required: ["command"]
1707
+ required: ["query"]
1705
1708
  }
1706
- },
1707
- {
1708
- name: "write_file",
1709
- description: "Write content to a file. Creates parent directories if needed. Use for creating HTML, CSS, JS, config files, etc.",
1710
- input_schema: {
1711
- type: "object",
1712
- properties: {
1713
- path: { type: "string", description: "File path relative to working directory" },
1714
- content: { type: "string", description: "Full file content to write" }
1709
+ };
1710
+ async execute(input, _cwd) {
1711
+ const query = String(input.query ?? "");
1712
+ const n = Math.min(10, Number(input.num_results ?? 5));
1713
+ const start = Date.now();
1714
+ try {
1715
+ const output = await this.ddgHtml(query, n);
1716
+ if (output && output.length > 50) {
1717
+ return { success: true, output, duration_ms: Date.now() - start };
1718
+ }
1719
+ } catch {
1720
+ }
1721
+ try {
1722
+ const output = await this.browserSearch(query, n);
1723
+ return { success: true, output, fallback_used: "browser", duration_ms: Date.now() - start };
1724
+ } catch (err) {
1725
+ return {
1726
+ success: false,
1727
+ output: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
1728
+ duration_ms: Date.now() - start
1729
+ };
1730
+ }
1731
+ }
1732
+ async ddgHtml(query, n) {
1733
+ const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}&kl=us-en`;
1734
+ const res = await fetch(url, {
1735
+ headers: {
1736
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0 Safari/537.36",
1737
+ "Accept": "text/html",
1738
+ "Accept-Language": "en-US,en;q=0.9"
1715
1739
  },
1716
- required: ["path", "content"]
1740
+ signal: AbortSignal.timeout(1e4)
1741
+ });
1742
+ const html = await res.text();
1743
+ const titleRe = /<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
1744
+ const snippetRe = /<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
1745
+ const titles = [];
1746
+ const snippets = [];
1747
+ let m;
1748
+ while ((m = titleRe.exec(html)) !== null && titles.length < n) {
1749
+ let href = m[1];
1750
+ const title = m[2].replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").trim();
1751
+ const uddg = href.match(/[?&]uddg=([^&]+)/);
1752
+ if (uddg) href = decodeURIComponent(uddg[1]);
1753
+ if (href.startsWith("http") && title) titles.push({ url: href, title });
1754
+ }
1755
+ while ((m = snippetRe.exec(html)) !== null && snippets.length < n) {
1756
+ snippets.push(m[1].replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim());
1757
+ }
1758
+ if (titles.length === 0) throw new Error("No results parsed from DDG");
1759
+ return titles.map(
1760
+ (t, i) => `${i + 1}. ${t.title}
1761
+ URL: ${t.url}${snippets[i] ? `
1762
+ ${snippets[i]}` : ""}`
1763
+ ).join("\n\n");
1764
+ }
1765
+ async browserSearch(query, n) {
1766
+ const searchUrl = `https://duckduckgo.com/?q=${encodeURIComponent(query)}`;
1767
+ try {
1768
+ const result = spawnSync("node", ["-e", `
1769
+ const { chromium } = require('playwright');
1770
+ (async () => {
1771
+ const b = await chromium.launch({ headless: true });
1772
+ const p = await b.newPage();
1773
+ await p.goto('${searchUrl}', { timeout: 15000 });
1774
+ await p.waitForSelector('[data-result]', { timeout: 8000 }).catch(() => {});
1775
+ const results = await p.$$eval('[data-result]', els =>
1776
+ els.slice(0, ${n}).map(el => ({
1777
+ title: el.querySelector('h2')?.innerText ?? '',
1778
+ url: el.querySelector('a')?.href ?? '',
1779
+ snippet: el.querySelector('[data-result="snippet"]')?.innerText ?? ''
1780
+ }))
1781
+ );
1782
+ await b.close();
1783
+ console.log(JSON.stringify(results));
1784
+ })();
1785
+ `], { timeout: 25e3, encoding: "utf8" });
1786
+ if (result.status === 0 && result.stdout) {
1787
+ const results = JSON.parse(result.stdout);
1788
+ return results.map(
1789
+ (r, i) => `${i + 1}. ${r.title}
1790
+ URL: ${r.url}${r.snippet ? `
1791
+ ${r.snippet}` : ""}`
1792
+ ).join("\n\n");
1793
+ }
1794
+ } catch {
1795
+ }
1796
+ const chrome = this.findChrome();
1797
+ if (chrome) {
1798
+ const result = spawnSync(chrome, [
1799
+ "--headless",
1800
+ "--no-sandbox",
1801
+ "--disable-gpu",
1802
+ `--dump-dom`,
1803
+ searchUrl
1804
+ ], { timeout: 15e3, encoding: "utf8" });
1805
+ if (result.stdout) {
1806
+ const html = result.stdout;
1807
+ const titles = [...html.matchAll(/<h2[^>]*>([\s\S]*?)<\/h2>/g)].map((m) => m[1].replace(/<[^>]+>/g, "").trim()).filter((t) => t.length > 5).slice(0, n);
1808
+ if (titles.length > 0) return titles.map((t, i) => `${i + 1}. ${t}`).join("\n");
1809
+ }
1810
+ }
1811
+ throw new Error("No browser available for fallback search");
1812
+ }
1813
+ findChrome() {
1814
+ const candidates = [
1815
+ "google-chrome",
1816
+ "google-chrome-stable",
1817
+ "chromium-browser",
1818
+ "chromium",
1819
+ "/usr/bin/google-chrome",
1820
+ "/usr/bin/chromium-browser",
1821
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
1822
+ ];
1823
+ for (const c of candidates) {
1824
+ try {
1825
+ execSync(`which "${c}" 2>/dev/null || test -f "${c}"`, { stdio: "pipe" });
1826
+ return c;
1827
+ } catch {
1828
+ }
1717
1829
  }
1718
- },
1719
- {
1720
- name: "read_file",
1721
- description: "Read a file's contents.",
1830
+ return null;
1831
+ }
1832
+ };
1833
+
1834
+ // packages/daemon/src/capabilities/BrowserCapability.ts
1835
+ import { spawnSync as spawnSync2, execSync as execSync2 } from "node:child_process";
1836
+ var BrowserCapability = class {
1837
+ name = "browser_open";
1838
+ description = "Open a URL in a real browser. Returns page content, can take screenshots. Use when scrape_url fails on JS-heavy pages.";
1839
+ toolDefinition = {
1840
+ name: "browser_open",
1841
+ description: "Open a URL in a real headless browser. Handles JavaScript-rendered pages, SPAs, login flows. Use when scrape_url fails.",
1722
1842
  input_schema: {
1723
1843
  type: "object",
1724
1844
  properties: {
1725
- path: { type: "string", description: "File path relative to working directory" }
1845
+ url: { type: "string", description: "URL to open" },
1846
+ action: { type: "string", description: 'What to do: "read" (default), "screenshot", "click <selector>", "fill <selector> <value>"' },
1847
+ wait_for: { type: "string", description: "CSS selector to wait for before extracting content" },
1848
+ extract: { type: "string", description: "CSS selector to extract specific element text" }
1726
1849
  },
1727
- required: ["path"]
1850
+ required: ["url"]
1851
+ }
1852
+ };
1853
+ async execute(input, _cwd) {
1854
+ const url = String(input.url ?? "");
1855
+ const action = String(input.action ?? "read");
1856
+ const waitFor = input.wait_for ? String(input.wait_for) : null;
1857
+ const extract = input.extract ? String(input.extract) : null;
1858
+ const start = Date.now();
1859
+ if (!url.startsWith("http")) {
1860
+ return { success: false, output: "URL must start with http:// or https://", duration_ms: 0 };
1861
+ }
1862
+ try {
1863
+ const output = await this.playwrightFetch(url, action, waitFor, extract);
1864
+ return { success: true, output, duration_ms: Date.now() - start };
1865
+ } catch {
1866
+ }
1867
+ try {
1868
+ const output = await this.chromeFetch(url);
1869
+ return { success: true, output, fallback_used: "system-chrome", duration_ms: Date.now() - start };
1870
+ } catch {
1871
+ }
1872
+ try {
1873
+ const res = await fetch(url, {
1874
+ headers: {
1875
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0 Safari/537.36",
1876
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
1877
+ "Accept-Language": "en-US,en;q=0.9",
1878
+ "Accept-Encoding": "gzip, deflate, br"
1879
+ },
1880
+ signal: AbortSignal.timeout(15e3)
1881
+ });
1882
+ const text = await res.text();
1883
+ const plain = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 5e3);
1884
+ return { success: true, output: plain, fallback_used: "fetch", duration_ms: Date.now() - start };
1885
+ } catch (err) {
1886
+ return {
1887
+ success: false,
1888
+ output: `Browser unavailable. Install Playwright: npx playwright install chromium`,
1889
+ error: err instanceof Error ? err.message : String(err),
1890
+ duration_ms: Date.now() - start
1891
+ };
1892
+ }
1893
+ }
1894
+ async playwrightFetch(url, action, waitFor, extract) {
1895
+ const waitLine = waitFor ? `await p.waitForSelector('${waitFor}', { timeout: 8000 }).catch(() => {});` : "";
1896
+ const extractLine = extract ? `const text = await p.$eval('${extract}', el => el.innerText).catch(() => page_text);` : `const text = page_text;`;
1897
+ const script = `
1898
+ const { chromium } = require('playwright');
1899
+ (async () => {
1900
+ const b = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
1901
+ const p = await b.newPage();
1902
+ await p.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36');
1903
+ await p.goto('${url}', { waitUntil: 'domcontentloaded', timeout: 20000 });
1904
+ ${waitLine}
1905
+ const page_text = await p.evaluate(() => document.body.innerText ?? '');
1906
+ ${extractLine}
1907
+ console.log(text.slice(0, 6000));
1908
+ await b.close();
1909
+ })().catch(e => { console.error(e.message); process.exit(1); });
1910
+ `;
1911
+ const result = spawnSync2("node", ["-e", script], { timeout: 3e4, encoding: "utf8" });
1912
+ if (result.status !== 0) throw new Error(result.stderr || "Playwright failed");
1913
+ return result.stdout.trim();
1914
+ }
1915
+ async chromeFetch(url) {
1916
+ const candidates = [
1917
+ "google-chrome",
1918
+ "chromium-browser",
1919
+ "chromium",
1920
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
1921
+ ];
1922
+ for (const chrome of candidates) {
1923
+ try {
1924
+ execSync2(`which "${chrome}" 2>/dev/null || test -f "${chrome}"`, { stdio: "pipe" });
1925
+ const result = spawnSync2(chrome, ["--headless", "--no-sandbox", "--disable-gpu", "--dump-dom", url], {
1926
+ timeout: 15e3,
1927
+ encoding: "utf8"
1928
+ });
1929
+ if (result.status === 0 && result.stdout) {
1930
+ return result.stdout.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 5e3);
1931
+ }
1932
+ } catch {
1933
+ }
1728
1934
  }
1729
- },
1730
- {
1731
- name: "list_dir",
1732
- description: "List files and directories.",
1935
+ throw new Error("No system Chrome found");
1936
+ }
1937
+ };
1938
+
1939
+ // packages/daemon/src/capabilities/ScraperCapability.ts
1940
+ import { spawnSync as spawnSync3 } from "node:child_process";
1941
+ var ScraperCapability = class {
1942
+ name = "scrape_url";
1943
+ description = "Scrape a URL. Tries fast HTTP fetch, then Scrapling, then browser if needed.";
1944
+ browser = new BrowserCapability();
1945
+ toolDefinition = {
1946
+ name: "scrape_url",
1947
+ description: "Scrape a URL and return clean content. Handles JS-rendered pages. Fallback chain: HTTP \u2192 Scrapling \u2192 Browser.",
1733
1948
  input_schema: {
1734
1949
  type: "object",
1735
1950
  properties: {
1736
- path: { type: "string", description: 'Directory path relative to working directory (default: ".")' }
1951
+ url: { type: "string", description: "URL to scrape" },
1952
+ mode: { type: "string", description: '"text" (default), "links", "tables", "markdown"' },
1953
+ selector: { type: "string", description: "Optional CSS selector to target element" }
1954
+ },
1955
+ required: ["url"]
1956
+ }
1957
+ };
1958
+ async execute(input, cwd) {
1959
+ const url = String(input.url ?? "");
1960
+ const mode = String(input.mode ?? "text");
1961
+ const selector = input.selector ? String(input.selector) : null;
1962
+ const start = Date.now();
1963
+ if (!url.startsWith("http")) {
1964
+ return { success: false, output: "URL must start with http:// or https://", duration_ms: 0 };
1965
+ }
1966
+ try {
1967
+ const output = await this.plainFetch(url, mode, selector);
1968
+ if (output && output.length > 100) {
1969
+ return { success: true, output, duration_ms: Date.now() - start };
1737
1970
  }
1971
+ } catch {
1738
1972
  }
1739
- },
1740
- {
1741
- name: "web_search",
1742
- description: "Search the web and return titles, URLs, and snippets. No API key needed. Use this first to find relevant pages, then scrape_url for full content.",
1973
+ try {
1974
+ const output = await this.scraplingFetch(url, mode);
1975
+ if (output && output.length > 100) {
1976
+ return { success: true, output, fallback_used: "scrapling", duration_ms: Date.now() - start };
1977
+ }
1978
+ } catch {
1979
+ }
1980
+ const browserResult = await this.browser.execute({ url, extract: selector ?? void 0 }, cwd);
1981
+ return { ...browserResult, fallback_used: "browser", duration_ms: Date.now() - start };
1982
+ }
1983
+ async plainFetch(url, mode, selector) {
1984
+ const res = await fetch(url, {
1985
+ headers: { "User-Agent": "Mozilla/5.0 AppleWebKit/537.36 Chrome/120.0" },
1986
+ signal: AbortSignal.timeout(12e3)
1987
+ });
1988
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
1989
+ const html = await res.text();
1990
+ if (mode === "links") {
1991
+ const links = [...html.matchAll(/href="(https?:\/\/[^"]+)"/g)].map((m) => m[1]).filter((v, i, a) => a.indexOf(v) === i).slice(0, 30);
1992
+ return links.join("\n");
1993
+ }
1994
+ if (mode === "tables") {
1995
+ const tables = [...html.matchAll(/<table[\s\S]*?<\/table>/gi)].map(
1996
+ (m) => m[0].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim()
1997
+ ).slice(0, 5);
1998
+ return tables.join("\n---\n");
1999
+ }
2000
+ const text = html.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
2001
+ return text.slice(0, 6e3) + (text.length > 6e3 ? "\n\u2026[truncated]" : "");
2002
+ }
2003
+ async scraplingFetch(url, mode) {
2004
+ const extractLine = mode === "links" ? `result = [a.attrib.get('href','') for a in page.find_all('a') if a.attrib.get('href','').startswith('http')]` : `result = page.get_all_text()`;
2005
+ const script = `
2006
+ import sys
2007
+ try:
2008
+ from scrapling import Fetcher
2009
+ except ImportError:
2010
+ import subprocess
2011
+ subprocess.run([sys.executable,'-m','pip','install','scrapling','-q'],check=True)
2012
+ from scrapling import Fetcher
2013
+ f = Fetcher(auto_match=False)
2014
+ page = f.get('${url}', timeout=20)
2015
+ ${extractLine}
2016
+ if isinstance(result, list):
2017
+ print('\\n'.join(str(r) for r in result[:30]))
2018
+ else:
2019
+ t = str(result).strip()
2020
+ print(t[:5000] + ('...' if len(t)>5000 else ''))
2021
+ `.trim();
2022
+ const result = spawnSync3("python3", ["-c", script], { timeout: 35e3, encoding: "utf8" });
2023
+ if (result.status !== 0) throw new Error(result.stderr || "Scrapling failed");
2024
+ return result.stdout.trim();
2025
+ }
2026
+ };
2027
+
2028
+ // packages/daemon/src/capabilities/ShellCapability.ts
2029
+ import { spawn } from "node:child_process";
2030
+ var ShellCapability = class {
2031
+ name = "shell_exec";
2032
+ description = "Execute shell commands in the working directory.";
2033
+ toolDefinition = {
2034
+ name: "shell_exec",
2035
+ description: "Execute a shell command. Use & for background processes. Returns stdout+stderr.",
1743
2036
  input_schema: {
1744
2037
  type: "object",
1745
2038
  properties: {
1746
- query: { type: "string", description: "Search query" },
1747
- num_results: { type: "number", description: "Number of results (default 5, max 10)" }
2039
+ command: { type: "string", description: "Shell command to execute" },
2040
+ timeout_ms: { type: "number", description: "Timeout (default 30000ms)" }
1748
2041
  },
1749
- required: ["query"]
2042
+ required: ["command"]
1750
2043
  }
1751
- },
1752
- {
1753
- name: "scrape_url",
1754
- description: "Scrape a URL and return clean structured content. Handles JavaScript-rendered pages, auto-adapts to page structure, returns text/links/metadata. Better than shell curl for web pages.",
2044
+ };
2045
+ async execute(input, cwd) {
2046
+ const command = String(input.command ?? "");
2047
+ const timeout = Number(input.timeout_ms ?? 3e4);
2048
+ const start = Date.now();
2049
+ return new Promise((resolve_) => {
2050
+ const chunks = [];
2051
+ const proc = spawn("bash", ["-c", command], {
2052
+ cwd,
2053
+ env: { ...process.env, TERM: "dumb" },
2054
+ timeout
2055
+ });
2056
+ proc.stdout.on("data", (d) => chunks.push(d.toString()));
2057
+ proc.stderr.on("data", (d) => chunks.push(d.toString()));
2058
+ proc.on("close", (code) => {
2059
+ const output = chunks.join("").trim();
2060
+ resolve_({
2061
+ success: code === 0,
2062
+ output: output || (code === 0 ? "(no output)" : `exit ${code}`),
2063
+ duration_ms: Date.now() - start,
2064
+ ...code !== 0 && { error: `exit code ${code}` }
2065
+ });
2066
+ });
2067
+ proc.on("error", (err) => {
2068
+ resolve_({ success: false, output: err.message, error: err.message, duration_ms: Date.now() - start });
2069
+ });
2070
+ });
2071
+ }
2072
+ };
2073
+
2074
+ // packages/daemon/src/capabilities/FileCapability.ts
2075
+ import { readFileSync as readFileSync2, writeFileSync, readdirSync, mkdirSync, existsSync as existsSync2 } from "node:fs";
2076
+ import { resolve as resolve2, dirname } from "node:path";
2077
+ var FileCapability = class {
2078
+ name = "file_op";
2079
+ description = "Read, write, or list files. Scoped to working directory.";
2080
+ toolDefinition = {
2081
+ name: "file_op",
2082
+ description: "Read, write, or list files in the working directory.",
1755
2083
  input_schema: {
1756
2084
  type: "object",
1757
2085
  properties: {
1758
- url: { type: "string", description: "URL to scrape" },
1759
- mode: { type: "string", description: 'What to extract: "text" (default), "links", "tables", "full", "markdown"' },
1760
- selector: { type: "string", description: "Optional CSS selector to target specific element" },
1761
- wait_ms: { type: "number", description: "Wait N ms after page load (for JS-heavy pages, default 0)" }
2086
+ op: { type: "string", description: '"read", "write", or "list"' },
2087
+ path: { type: "string", description: "File or directory path (relative to cwd)" },
2088
+ content: { type: "string", description: "Content for write operation" }
1762
2089
  },
1763
- required: ["url"]
2090
+ required: ["op", "path"]
2091
+ }
2092
+ };
2093
+ async execute(input, cwd) {
2094
+ const op = String(input.op ?? "read");
2095
+ const rel = String(input.path ?? ".");
2096
+ const safe = resolve2(cwd, rel);
2097
+ const start = Date.now();
2098
+ if (!safe.startsWith(cwd)) {
2099
+ return { success: false, output: "Path outside working directory", duration_ms: 0 };
2100
+ }
2101
+ try {
2102
+ if (op === "read") {
2103
+ if (!existsSync2(safe)) return { success: false, output: `Not found: ${rel}`, duration_ms: Date.now() - start };
2104
+ const content = readFileSync2(safe, "utf8");
2105
+ return {
2106
+ success: true,
2107
+ output: content.length > 8e3 ? content.slice(0, 8e3) + "\n\u2026[truncated]" : content,
2108
+ duration_ms: Date.now() - start
2109
+ };
2110
+ }
2111
+ if (op === "write") {
2112
+ mkdirSync(dirname(safe), { recursive: true });
2113
+ writeFileSync(safe, String(input.content ?? ""), "utf8");
2114
+ return { success: true, output: `Written: ${rel} (${String(input.content ?? "").length} bytes)`, duration_ms: Date.now() - start };
2115
+ }
2116
+ if (op === "list") {
2117
+ if (!existsSync2(safe)) return { success: false, output: `Not found: ${rel}`, duration_ms: Date.now() - start };
2118
+ const entries = readdirSync(safe, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`).join("\n");
2119
+ return { success: true, output: entries || "(empty)", duration_ms: Date.now() - start };
2120
+ }
2121
+ return { success: false, output: `Unknown op: ${op}`, duration_ms: Date.now() - start };
2122
+ } catch (err) {
2123
+ return { success: false, output: `Error: ${err instanceof Error ? err.message : String(err)}`, duration_ms: Date.now() - start };
1764
2124
  }
1765
2125
  }
1766
- ];
1767
- var LLMExecutor = class {
1768
- constructor(config) {
1769
- this.config = config;
2126
+ };
2127
+
2128
+ // packages/daemon/src/capabilities/CapabilityRegistry.ts
2129
+ var CapabilityRegistry = class {
2130
+ capabilities = /* @__PURE__ */ new Map();
2131
+ constructor() {
2132
+ this.register(new WebSearchCapability());
2133
+ this.register(new BrowserCapability());
2134
+ this.register(new ScraperCapability());
2135
+ this.register(new ShellCapability());
2136
+ this.register(new FileCapability());
1770
2137
  }
1771
- get isConfigured() {
1772
- if (this.config.provider === "ollama") return true;
1773
- return !!this.config.api_key?.trim();
2138
+ register(cap) {
2139
+ this.capabilities.set(cap.name, cap);
1774
2140
  }
1775
- // ─── Single completion (no tools, no streaming) ──────────────────────────
1776
- async complete(messages, system) {
1777
- const res = await this.completeWithTools(messages, [], system, void 0);
1778
- return { content: res.content, tokens_used: res.tokens_used, model: res.model };
2141
+ get(name) {
2142
+ return this.capabilities.get(name);
1779
2143
  }
1780
- // ─── Tool-calling completion with optional streaming ─────────────────────
1781
- async completeWithTools(messages, tools, system, onToken) {
1782
- switch (this.config.provider) {
1783
- case "anthropic":
1784
- return this.anthropic(messages, tools, system, onToken);
1785
- case "openai":
1786
- return this.openai(messages, tools, system, onToken);
1787
- case "xai":
1788
- return this.openai(messages, tools, system, onToken, "https://api.x.ai/v1");
1789
- case "gemini":
1790
- return this.openai(messages, tools, system, onToken, "https://generativelanguage.googleapis.com/v1beta/openai");
1791
- case "ollama":
1792
- return this.ollama(messages, system, onToken);
1793
- default:
1794
- return this.openai(messages, tools, system, onToken);
2144
+ getToolDefinitions() {
2145
+ return [...this.capabilities.values()].map((c) => c.toolDefinition);
2146
+ }
2147
+ async execute(toolName, input, cwd) {
2148
+ const cap = this.capabilities.get(toolName);
2149
+ if (!cap) {
2150
+ return { success: false, output: `Unknown capability: ${toolName}`, duration_ms: 0 };
2151
+ }
2152
+ try {
2153
+ return await cap.execute(input, cwd);
2154
+ } catch (err) {
2155
+ return {
2156
+ success: false,
2157
+ output: `Capability error: ${err instanceof Error ? err.message : String(err)}`,
2158
+ duration_ms: 0
2159
+ };
1795
2160
  }
1796
2161
  }
1797
- // ─── Anthropic ───────────────────────────────────────────────────────────
1798
- async anthropic(messages, tools, system, onToken) {
1799
- const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
1800
- const filtered = messages.filter((m) => m.role !== "system");
1801
- const anthropicMsgs = filtered.map((m) => {
1802
- if (m.role === "tool") {
1803
- return {
1804
- role: "user",
1805
- content: [{ type: "tool_result", tool_use_id: m.tool_call_id, content: m.content }]
1806
- };
2162
+ list() {
2163
+ return [...this.capabilities.values()].map((c) => ({ name: c.name, description: c.description }));
2164
+ }
2165
+ };
2166
+
2167
+ // packages/daemon/src/AgentExecutor.ts
2168
+ var AgentExecutor = class {
2169
+ constructor(llm, config, onStep, onToken) {
2170
+ this.llm = llm;
2171
+ this.config = config;
2172
+ this.onStep = onStep;
2173
+ this.onToken = onToken;
2174
+ this.cwd = config.cwd;
2175
+ this.maxIterations = config.max_iterations ?? 20;
2176
+ this.maxCommandMs = config.max_command_ms ?? 3e4;
2177
+ this.registry = new CapabilityRegistry();
2178
+ }
2179
+ cwd;
2180
+ maxIterations;
2181
+ maxCommandMs;
2182
+ registry;
2183
+ async execute(task, systemContext) {
2184
+ const filesWritten = [];
2185
+ const commandsRun = [];
2186
+ let totalTokens = 0;
2187
+ let modelName = "";
2188
+ const systemPrompt = this.buildSystemPrompt(systemContext);
2189
+ const messages = [
2190
+ { role: "user", content: task }
2191
+ ];
2192
+ let finalOutput = "";
2193
+ for (let i = 0; i < this.maxIterations; i++) {
2194
+ this.onStep(i === 0 ? "Thinking\u2026" : "Continuing\u2026");
2195
+ let response;
2196
+ try {
2197
+ response = await this.llm.completeWithTools(
2198
+ messages,
2199
+ this.registry.getToolDefinitions(),
2200
+ systemPrompt,
2201
+ // Only stream tokens on the final (non-tool) turn
2202
+ (token) => {
2203
+ this.onToken(token);
2204
+ finalOutput += token;
2205
+ }
2206
+ );
2207
+ } catch (err) {
2208
+ const msg = err instanceof Error ? err.message : String(err);
2209
+ this.onStep(`LLM error: ${msg}`);
2210
+ finalOutput = `Error: ${msg}`;
2211
+ break;
1807
2212
  }
1808
- if (m.role === "assistant" && m.tool_calls?.length) {
1809
- return {
1810
- role: "assistant",
1811
- content: [
1812
- ...m.content ? [{ type: "text", text: m.content }] : [],
1813
- ...m.tool_calls.map((tc) => ({
1814
- type: "tool_use",
1815
- id: tc.id,
1816
- name: tc.name,
1817
- input: tc.input
1818
- }))
1819
- ]
1820
- };
1821
- }
1822
- return { role: m.role, content: m.content };
1823
- });
1824
- const body = {
1825
- model: this.config.model,
1826
- max_tokens: 8192,
1827
- messages: anthropicMsgs,
1828
- stream: true
1829
- };
1830
- if (sysContent) body.system = sysContent;
1831
- if (tools.length > 0) {
1832
- body.tools = tools.map((t) => ({
1833
- name: t.name,
1834
- description: t.description,
1835
- input_schema: t.input_schema
1836
- }));
1837
- }
1838
- const res = await fetch("https://api.anthropic.com/v1/messages", {
1839
- method: "POST",
1840
- headers: {
1841
- "Content-Type": "application/json",
1842
- "x-api-key": this.config.api_key,
1843
- "anthropic-version": "2023-06-01"
1844
- },
1845
- body: JSON.stringify(body)
1846
- });
1847
- if (!res.ok) {
1848
- const err = await res.text();
1849
- throw new Error(`Anthropic ${res.status}: ${err}`);
1850
- }
1851
- let textContent = "";
1852
- let stopReason = "end_turn";
1853
- let inputTokens = 0;
1854
- let outputTokens = 0;
1855
- let modelName = this.config.model;
1856
- const toolCalls = [];
1857
- const toolInputBuffers = {};
1858
- let currentToolId = "";
1859
- const reader = res.body.getReader();
1860
- const decoder = new TextDecoder();
1861
- let buf = "";
1862
- while (true) {
1863
- const { done, value } = await reader.read();
1864
- if (done) break;
1865
- buf += decoder.decode(value, { stream: true });
1866
- const lines = buf.split("\n");
1867
- buf = lines.pop() ?? "";
1868
- for (const line of lines) {
1869
- if (!line.startsWith("data: ")) continue;
1870
- const data = line.slice(6).trim();
1871
- if (data === "[DONE]" || data === "") continue;
1872
- let evt;
1873
- try {
1874
- evt = JSON.parse(data);
1875
- } catch {
1876
- continue;
1877
- }
1878
- const type = evt.type;
1879
- if (type === "message_start") {
1880
- const usage = evt.message?.usage;
1881
- inputTokens = usage?.input_tokens ?? 0;
1882
- modelName = evt.message?.model ?? modelName;
1883
- } else if (type === "content_block_start") {
1884
- const block = evt.content_block;
1885
- if (block?.type === "tool_use") {
1886
- currentToolId = block.id;
1887
- toolInputBuffers[currentToolId] = "";
1888
- toolCalls.push({ id: currentToolId, name: block.name, input: {} });
1889
- }
1890
- } else if (type === "content_block_delta") {
1891
- const delta = evt.delta;
1892
- if (delta?.type === "text_delta") {
1893
- const token = delta.text ?? "";
1894
- textContent += token;
1895
- if (onToken && token) onToken(token);
1896
- } else if (delta?.type === "input_json_delta") {
1897
- toolInputBuffers[currentToolId] = (toolInputBuffers[currentToolId] ?? "") + (delta.partial_json ?? "");
1898
- }
1899
- } else if (type === "content_block_stop") {
1900
- if (currentToolId && toolInputBuffers[currentToolId]) {
1901
- const tc = toolCalls.find((t) => t.id === currentToolId);
1902
- if (tc) {
1903
- try {
1904
- tc.input = JSON.parse(toolInputBuffers[currentToolId]);
1905
- } catch {
1906
- }
1907
- }
1908
- }
1909
- } else if (type === "message_delta") {
1910
- const usage = evt.usage;
1911
- outputTokens = usage?.output_tokens ?? 0;
1912
- const stop = evt.delta?.stop_reason;
1913
- if (stop === "tool_use") stopReason = "tool_use";
1914
- else if (stop === "end_turn") stopReason = "end_turn";
1915
- else if (stop === "max_tokens") stopReason = "max_tokens";
1916
- }
1917
- }
1918
- }
1919
- return {
1920
- content: textContent,
1921
- tool_calls: toolCalls.length > 0 ? toolCalls : null,
1922
- stop_reason: stopReason,
1923
- tokens_used: inputTokens + outputTokens,
1924
- model: modelName
1925
- };
1926
- }
1927
- // ─── OpenAI (also xAI, Gemini) ───────────────────────────────────────────
1928
- async openai(messages, tools, system, onToken, baseUrl = "https://api.openai.com/v1") {
1929
- const allMessages = [];
1930
- const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
1931
- if (sysContent) allMessages.push({ role: "system", content: sysContent });
1932
- for (const m of messages.filter((m2) => m2.role !== "system")) {
1933
- if (m.role === "tool") {
1934
- allMessages.push({ role: "tool", tool_call_id: m.tool_call_id, content: m.content });
1935
- } else if (m.role === "assistant" && m.tool_calls?.length) {
1936
- allMessages.push({
1937
- role: "assistant",
1938
- content: m.content || null,
1939
- tool_calls: m.tool_calls.map((tc) => ({
1940
- id: tc.id,
1941
- type: "function",
1942
- function: { name: tc.name, arguments: JSON.stringify(tc.input) }
1943
- }))
1944
- });
1945
- } else {
1946
- allMessages.push({ role: m.role, content: m.content });
1947
- }
1948
- }
1949
- const body = {
1950
- model: this.config.model,
1951
- messages: allMessages,
1952
- max_tokens: 8192,
1953
- stream: true,
1954
- stream_options: { include_usage: true }
1955
- };
1956
- if (tools.length > 0) {
1957
- body.tools = tools.map((t) => ({
1958
- type: "function",
1959
- function: { name: t.name, description: t.description, parameters: t.input_schema }
1960
- }));
1961
- }
1962
- const res = await fetch(`${this.config.base_url ?? baseUrl}/chat/completions`, {
1963
- method: "POST",
1964
- headers: {
1965
- "Content-Type": "application/json",
1966
- "Authorization": `Bearer ${this.config.api_key}`
1967
- },
1968
- body: JSON.stringify(body)
1969
- });
1970
- if (!res.ok) {
1971
- const err = await res.text();
1972
- throw new Error(`OpenAI ${res.status}: ${err}`);
1973
- }
1974
- let textContent = "";
1975
- let tokensUsed = 0;
1976
- let modelName = this.config.model;
1977
- let stopReason = "end_turn";
1978
- const toolCallMap = {};
1979
- const reader = res.body.getReader();
1980
- const decoder = new TextDecoder();
1981
- let buf = "";
1982
- while (true) {
1983
- const { done, value } = await reader.read();
1984
- if (done) break;
1985
- buf += decoder.decode(value, { stream: true });
1986
- const lines = buf.split("\n");
1987
- buf = lines.pop() ?? "";
1988
- for (const line of lines) {
1989
- if (!line.startsWith("data: ")) continue;
1990
- const data = line.slice(6).trim();
1991
- if (data === "[DONE]") continue;
1992
- let evt;
1993
- try {
1994
- evt = JSON.parse(data);
1995
- } catch {
1996
- continue;
1997
- }
1998
- modelName = evt.model ?? modelName;
1999
- const usage = evt.usage;
2000
- if (usage?.total_tokens) tokensUsed = usage.total_tokens;
2001
- const choices = evt.choices;
2002
- if (!choices?.length) continue;
2003
- const delta = choices[0].delta;
2004
- if (!delta) continue;
2005
- const finish = choices[0].finish_reason;
2006
- if (finish === "tool_calls") stopReason = "tool_use";
2007
- else if (finish === "stop") stopReason = "end_turn";
2008
- const token = delta.content;
2009
- if (token) {
2010
- textContent += token;
2011
- if (onToken) onToken(token);
2012
- }
2013
- const toolCallDeltas = delta.tool_calls;
2014
- if (toolCallDeltas) {
2015
- for (const tc of toolCallDeltas) {
2016
- const idx = tc.index;
2017
- if (!toolCallMap[idx]) {
2018
- toolCallMap[idx] = { id: "", name: "", args: "" };
2019
- }
2020
- const fn = tc.function;
2021
- if (tc.id) toolCallMap[idx].id = tc.id;
2022
- if (fn?.name) toolCallMap[idx].name = fn.name;
2023
- if (fn?.arguments) toolCallMap[idx].args += fn.arguments;
2024
- }
2025
- }
2026
- }
2027
- }
2028
- const toolCalls = Object.values(toolCallMap).filter((tc) => tc.id && tc.name).map((tc) => {
2029
- let input = {};
2030
- try {
2031
- input = JSON.parse(tc.args);
2032
- } catch {
2033
- }
2034
- return { id: tc.id, name: tc.name, input };
2035
- });
2036
- return {
2037
- content: textContent,
2038
- tool_calls: toolCalls.length > 0 ? toolCalls : null,
2039
- stop_reason: stopReason,
2040
- tokens_used: tokensUsed,
2041
- model: modelName
2042
- };
2043
- }
2044
- // ─── Ollama (no streaming for simplicity) ────────────────────────────────
2045
- async ollama(messages, system, onToken) {
2046
- const baseUrl = this.config.base_url ?? "http://localhost:11434";
2047
- const allMessages = [];
2048
- const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
2049
- if (sysContent) allMessages.push({ role: "system", content: sysContent });
2050
- allMessages.push(...messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content })));
2051
- const res = await fetch(`${baseUrl}/api/chat`, {
2052
- method: "POST",
2053
- headers: { "Content-Type": "application/json" },
2054
- body: JSON.stringify({ model: this.config.model, messages: allMessages, stream: false })
2055
- });
2056
- if (!res.ok) throw new Error(`Ollama error ${res.status}`);
2057
- const data = await res.json();
2058
- if (onToken) onToken(data.message.content);
2059
- return { content: data.message.content, tool_calls: null, stop_reason: "end_turn", tokens_used: data.eval_count ?? 0, model: this.config.model };
2060
- }
2061
- };
2062
-
2063
- // packages/daemon/src/AgentExecutor.ts
2064
- var AgentExecutor = class {
2065
- constructor(llm, config, onStep, onToken) {
2066
- this.llm = llm;
2067
- this.config = config;
2068
- this.onStep = onStep;
2069
- this.onToken = onToken;
2070
- this.cwd = config.cwd;
2071
- this.maxIterations = config.max_iterations ?? 20;
2072
- this.maxCommandMs = config.max_command_ms ?? 3e4;
2073
- }
2074
- cwd;
2075
- maxIterations;
2076
- maxCommandMs;
2077
- async execute(task, systemContext) {
2078
- const filesWritten = [];
2079
- const commandsRun = [];
2080
- let totalTokens = 0;
2081
- let modelName = "";
2082
- const systemPrompt = this.buildSystemPrompt(systemContext);
2083
- const messages = [
2084
- { role: "user", content: task }
2085
- ];
2086
- let finalOutput = "";
2087
- for (let i = 0; i < this.maxIterations; i++) {
2088
- this.onStep(i === 0 ? "Thinking\u2026" : "Continuing\u2026");
2089
- let response;
2090
- try {
2091
- response = await this.llm.completeWithTools(
2092
- messages,
2093
- AGENT_TOOLS,
2094
- systemPrompt,
2095
- // Only stream tokens on the final (non-tool) turn
2096
- (token) => {
2097
- this.onToken(token);
2098
- finalOutput += token;
2099
- }
2100
- );
2101
- } catch (err) {
2102
- const msg = err instanceof Error ? err.message : String(err);
2103
- this.onStep(`LLM error: ${msg}`);
2104
- finalOutput = `Error: ${msg}`;
2105
- break;
2106
- }
2107
- totalTokens += response.tokens_used;
2108
- modelName = response.model;
2109
- if (response.stop_reason === "end_turn" || !response.tool_calls?.length) {
2110
- if (!finalOutput && response.content) finalOutput = response.content;
2111
- break;
2213
+ totalTokens += response.tokens_used;
2214
+ modelName = response.model;
2215
+ if (response.stop_reason === "end_turn" || !response.tool_calls?.length) {
2216
+ if (!finalOutput && response.content) finalOutput = response.content;
2217
+ break;
2112
2218
  }
2113
2219
  finalOutput = "";
2114
2220
  messages.push({
@@ -2120,8 +2226,12 @@ var AgentExecutor = class {
2120
2226
  this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)})`);
2121
2227
  let result;
2122
2228
  try {
2123
- result = await this.executeTool(tc.name, tc.input);
2124
- if (tc.name === "write_file" && tc.input.path) {
2229
+ const capResult = await this.registry.execute(tc.name, tc.input, this.cwd);
2230
+ result = capResult.output;
2231
+ if (capResult.fallback_used) {
2232
+ this.onStep(` (used fallback: ${capResult.fallback_used})`);
2233
+ }
2234
+ if (tc.name === "file_op" && tc.input.op === "write" && tc.input.path) {
2125
2235
  filesWritten.push(String(tc.input.path));
2126
2236
  }
2127
2237
  if (tc.name === "shell_exec" && tc.input.command) {
@@ -2178,9 +2288,9 @@ var AgentExecutor = class {
2178
2288
  }
2179
2289
  }
2180
2290
  shellExec(command, timeoutMs) {
2181
- return new Promise((resolve6) => {
2291
+ return new Promise((resolve7) => {
2182
2292
  const chunks = [];
2183
- const proc = spawn("bash", ["-c", command], {
2293
+ const proc = spawn2("bash", ["-c", command], {
2184
2294
  cwd: this.cwd,
2185
2295
  env: { ...process.env, TERM: "dumb" },
2186
2296
  timeout: timeoutMs
@@ -2189,26 +2299,26 @@ var AgentExecutor = class {
2189
2299
  proc.stderr.on("data", (d) => chunks.push(d.toString()));
2190
2300
  proc.on("close", (code) => {
2191
2301
  const output = chunks.join("").trim();
2192
- resolve6(output || (code === 0 ? "(command completed, no output)" : `exit code ${code}`));
2302
+ resolve7(output || (code === 0 ? "(command completed, no output)" : `exit code ${code}`));
2193
2303
  });
2194
2304
  proc.on("error", (err) => {
2195
- resolve6(`Error: ${err.message}`);
2305
+ resolve7(`Error: ${err.message}`);
2196
2306
  });
2197
2307
  });
2198
2308
  }
2199
2309
  writeFile(filePath, content) {
2200
2310
  const safe = this.safePath(filePath);
2201
2311
  if (!safe) return "Error: path outside working directory";
2202
- mkdirSync(dirname(safe), { recursive: true });
2203
- writeFileSync(safe, content, "utf8");
2312
+ mkdirSync2(dirname2(safe), { recursive: true });
2313
+ writeFileSync2(safe, content, "utf8");
2204
2314
  const rel = relative(this.cwd, safe);
2205
2315
  return `Written: ${rel} (${content.length} bytes)`;
2206
2316
  }
2207
2317
  readFile(filePath) {
2208
2318
  const safe = this.safePath(filePath);
2209
2319
  if (!safe) return "Error: path outside working directory";
2210
- if (!existsSync2(safe)) return `File not found: ${filePath}`;
2211
- const content = readFileSync2(safe, "utf8");
2320
+ if (!existsSync3(safe)) return `File not found: ${filePath}`;
2321
+ const content = readFileSync3(safe, "utf8");
2212
2322
  return content.length > 8e3 ? content.slice(0, 8e3) + `
2213
2323
  \u2026[truncated, ${content.length} total bytes]` : content;
2214
2324
  }
@@ -2299,9 +2409,9 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
2299
2409
  listDir(dirPath) {
2300
2410
  const safe = this.safePath(dirPath ?? ".");
2301
2411
  if (!safe) return "Error: path outside working directory";
2302
- if (!existsSync2(safe)) return `Directory not found: ${dirPath}`;
2412
+ if (!existsSync3(safe)) return `Directory not found: ${dirPath}`;
2303
2413
  try {
2304
- const entries = readdirSync(safe, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`).join("\n");
2414
+ const entries = readdirSync2(safe, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`).join("\n");
2305
2415
  return entries || "(empty directory)";
2306
2416
  } catch (e) {
2307
2417
  return `Error: ${e instanceof Error ? e.message : String(e)}`;
@@ -2309,7 +2419,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
2309
2419
  }
2310
2420
  // ─── Helpers ───────────────────────────────────────────────────────────────
2311
2421
  safePath(p) {
2312
- const resolved = resolve2(this.cwd, p);
2422
+ const resolved = resolve3(this.cwd, p);
2313
2423
  return resolved.startsWith(this.cwd) ? resolved : null;
2314
2424
  }
2315
2425
  buildSystemPrompt(extra) {
@@ -2794,7 +2904,7 @@ var BackgroundWorkers = class {
2794
2904
  };
2795
2905
 
2796
2906
  // packages/daemon/src/SkillRegistry.ts
2797
- import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "node:fs";
2907
+ import { readFileSync as readFileSync4, readdirSync as readdirSync3, existsSync as existsSync4, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync3 } from "node:fs";
2798
2908
  import { join } from "node:path";
2799
2909
  import { homedir as homedir2 } from "node:os";
2800
2910
  import YAML2 from "yaml";
@@ -2817,11 +2927,11 @@ var SkillRegistry = class {
2817
2927
  this.loadFromDir(this.customDir, false);
2818
2928
  }
2819
2929
  loadFromDir(dir, isBuiltin) {
2820
- if (!existsSync3(dir)) return;
2821
- const files = readdirSync2(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
2930
+ if (!existsSync4(dir)) return;
2931
+ const files = readdirSync3(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
2822
2932
  for (const file of files) {
2823
2933
  try {
2824
- const raw = readFileSync3(join(dir, file), "utf8");
2934
+ const raw = readFileSync4(join(dir, file), "utf8");
2825
2935
  const skill = YAML2.parse(raw);
2826
2936
  if (skill.name) {
2827
2937
  this.skills.set(skill.name, skill);
@@ -2856,9 +2966,9 @@ var SkillRegistry = class {
2856
2966
  if (this.builtinNames.has(name)) {
2857
2967
  throw new Error(`Cannot override built-in skill: ${name}`);
2858
2968
  }
2859
- mkdirSync2(this.customDir, { recursive: true });
2969
+ mkdirSync3(this.customDir, { recursive: true });
2860
2970
  const filePath = join(this.customDir, `${name}.yaml`);
2861
- writeFileSync2(filePath, yamlContent, "utf8");
2971
+ writeFileSync3(filePath, yamlContent, "utf8");
2862
2972
  const skill = YAML2.parse(yamlContent);
2863
2973
  this.skills.set(name, skill);
2864
2974
  return skill;
@@ -2871,7 +2981,7 @@ var SkillRegistry = class {
2871
2981
  throw new Error(`Cannot delete built-in skill: ${name}`);
2872
2982
  }
2873
2983
  const filePath = join(this.customDir, `${name}.yaml`);
2874
- if (existsSync3(filePath)) {
2984
+ if (existsSync4(filePath)) {
2875
2985
  unlinkSync(filePath);
2876
2986
  }
2877
2987
  this.skills.delete(name);
@@ -2884,8 +2994,8 @@ var SkillRegistry = class {
2884
2994
  // packages/daemon/src/HTTPServer.ts
2885
2995
  import { Hono as Hono8 } from "hono";
2886
2996
  import { serve } from "@hono/node-server";
2887
- import { readFileSync as readFileSync4 } from "node:fs";
2888
- import { resolve as resolve3, dirname as dirname2 } from "node:path";
2997
+ import { readFileSync as readFileSync5 } from "node:fs";
2998
+ import { resolve as resolve4, dirname as dirname3 } from "node:path";
2889
2999
  import { fileURLToPath } from "node:url";
2890
3000
 
2891
3001
  // packages/daemon/src/routes/health.ts
@@ -3116,99 +3226,396 @@ function skillRoutes(deps) {
3116
3226
  const message = err instanceof Error ? err.message : String(err);
3117
3227
  return c.json({ error: message }, 500);
3118
3228
  }
3119
- });
3120
- app.delete("/:name", (c) => {
3121
- const name = c.req.param("name");
3122
- if (deps.skillRegistry.isBuiltin(name)) {
3123
- return c.json({ error: "Cannot delete built-in skill" }, 403);
3229
+ });
3230
+ app.delete("/:name", (c) => {
3231
+ const name = c.req.param("name");
3232
+ if (deps.skillRegistry.isBuiltin(name)) {
3233
+ return c.json({ error: "Cannot delete built-in skill" }, 403);
3234
+ }
3235
+ const skill = deps.skillRegistry.get(name);
3236
+ if (!skill) {
3237
+ return c.json({ error: "Skill not found" }, 404);
3238
+ }
3239
+ try {
3240
+ deps.skillRegistry.removeCustom(name);
3241
+ return c.json({ ok: true });
3242
+ } catch (err) {
3243
+ const message = err instanceof Error ? err.message : String(err);
3244
+ return c.json({ error: message }, 500);
3245
+ }
3246
+ });
3247
+ return app;
3248
+ }
3249
+
3250
+ // packages/daemon/src/HTTPServer.ts
3251
+ function findGraphHtml() {
3252
+ const candidates = [
3253
+ resolve4(dirname3(fileURLToPath(import.meta.url)), "graph.html"),
3254
+ // dev (src/)
3255
+ resolve4(dirname3(fileURLToPath(import.meta.url)), "..", "graph.html"),
3256
+ // bundled (dist/../)
3257
+ resolve4(dirname3(fileURLToPath(import.meta.url)), "..", "dist", "graph.html")
3258
+ ];
3259
+ for (const p of candidates) {
3260
+ try {
3261
+ readFileSync5(p);
3262
+ return p;
3263
+ } catch {
3264
+ }
3265
+ }
3266
+ return candidates[0];
3267
+ }
3268
+ var GRAPH_HTML_PATH = findGraphHtml();
3269
+ var HTTPServer = class {
3270
+ app;
3271
+ server = null;
3272
+ deps;
3273
+ constructor(deps) {
3274
+ this.deps = deps;
3275
+ this.app = new Hono8();
3276
+ this.app.route("/api/health", healthRoutes({ getStatus: deps.getStatus }));
3277
+ this.app.route("/api/sessions", sessionRoutes({ sessions: deps.sessions }));
3278
+ this.app.route("/api/graph", graphRoutes({ graph: deps.graph }));
3279
+ this.app.route("/api/entities", entityRoutes({ graph: deps.graph }));
3280
+ this.app.route("/api/traces", traceRoutes({ traceStore: deps.traceStore }));
3281
+ this.app.route("/api/subagents", subagentRoutes());
3282
+ this.app.route("/api/skills", skillRoutes({ skillRegistry: deps.skillRegistry }));
3283
+ const serveGraph = (c) => {
3284
+ try {
3285
+ const html = readFileSync5(GRAPH_HTML_PATH, "utf8");
3286
+ return c.html(html);
3287
+ } catch {
3288
+ return c.html("<p>Graph UI not found. Run: pnpm build</p>");
3289
+ }
3290
+ };
3291
+ this.app.get("/", serveGraph);
3292
+ this.app.get("/graph", serveGraph);
3293
+ }
3294
+ start() {
3295
+ return new Promise((resolve7) => {
3296
+ this.server = serve(
3297
+ {
3298
+ fetch: this.app.fetch,
3299
+ port: this.deps.port,
3300
+ hostname: this.deps.host
3301
+ },
3302
+ () => {
3303
+ resolve7();
3304
+ }
3305
+ );
3306
+ });
3307
+ }
3308
+ stop() {
3309
+ return new Promise((resolve7, reject) => {
3310
+ if (!this.server) {
3311
+ resolve7();
3312
+ return;
3313
+ }
3314
+ this.server.close((err) => {
3315
+ if (err) reject(err);
3316
+ else resolve7();
3317
+ });
3318
+ });
3319
+ }
3320
+ getApp() {
3321
+ return this.app;
3322
+ }
3323
+ };
3324
+
3325
+ // packages/daemon/src/LLMExecutor.ts
3326
+ var LLMExecutor = class {
3327
+ constructor(config) {
3328
+ this.config = config;
3329
+ }
3330
+ get isConfigured() {
3331
+ if (this.config.provider === "ollama") return true;
3332
+ return !!this.config.api_key?.trim();
3333
+ }
3334
+ // ─── Single completion (no tools, no streaming) ──────────────────────────
3335
+ async complete(messages, system) {
3336
+ const res = await this.completeWithTools(messages, [], system, void 0);
3337
+ return { content: res.content, tokens_used: res.tokens_used, model: res.model };
3338
+ }
3339
+ // ─── Tool-calling completion with optional streaming ─────────────────────
3340
+ async completeWithTools(messages, tools, system, onToken) {
3341
+ switch (this.config.provider) {
3342
+ case "anthropic":
3343
+ return this.anthropic(messages, tools, system, onToken);
3344
+ case "openai":
3345
+ return this.openai(messages, tools, system, onToken);
3346
+ case "xai":
3347
+ return this.openai(messages, tools, system, onToken, "https://api.x.ai/v1");
3348
+ case "gemini":
3349
+ return this.openai(messages, tools, system, onToken, "https://generativelanguage.googleapis.com/v1beta/openai");
3350
+ case "ollama":
3351
+ return this.ollama(messages, system, onToken);
3352
+ default:
3353
+ return this.openai(messages, tools, system, onToken);
3354
+ }
3355
+ }
3356
+ // ─── Anthropic ───────────────────────────────────────────────────────────
3357
+ async anthropic(messages, tools, system, onToken) {
3358
+ const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
3359
+ const filtered = messages.filter((m) => m.role !== "system");
3360
+ const anthropicMsgs = filtered.map((m) => {
3361
+ if (m.role === "tool") {
3362
+ return {
3363
+ role: "user",
3364
+ content: [{ type: "tool_result", tool_use_id: m.tool_call_id, content: m.content }]
3365
+ };
3366
+ }
3367
+ if (m.role === "assistant" && m.tool_calls?.length) {
3368
+ return {
3369
+ role: "assistant",
3370
+ content: [
3371
+ ...m.content ? [{ type: "text", text: m.content }] : [],
3372
+ ...m.tool_calls.map((tc) => ({
3373
+ type: "tool_use",
3374
+ id: tc.id,
3375
+ name: tc.name,
3376
+ input: tc.input
3377
+ }))
3378
+ ]
3379
+ };
3380
+ }
3381
+ return { role: m.role, content: m.content };
3382
+ });
3383
+ const body = {
3384
+ model: this.config.model,
3385
+ max_tokens: 8192,
3386
+ messages: anthropicMsgs,
3387
+ stream: true
3388
+ };
3389
+ if (sysContent) body.system = sysContent;
3390
+ if (tools.length > 0) {
3391
+ body.tools = tools.map((t) => ({
3392
+ name: t.name,
3393
+ description: t.description,
3394
+ input_schema: t.input_schema
3395
+ }));
3396
+ }
3397
+ const res = await fetch("https://api.anthropic.com/v1/messages", {
3398
+ method: "POST",
3399
+ headers: {
3400
+ "Content-Type": "application/json",
3401
+ "x-api-key": this.config.api_key,
3402
+ "anthropic-version": "2023-06-01"
3403
+ },
3404
+ body: JSON.stringify(body)
3405
+ });
3406
+ if (!res.ok) {
3407
+ const err = await res.text();
3408
+ throw new Error(`Anthropic ${res.status}: ${err}`);
3409
+ }
3410
+ let textContent = "";
3411
+ let stopReason = "end_turn";
3412
+ let inputTokens = 0;
3413
+ let outputTokens = 0;
3414
+ let modelName = this.config.model;
3415
+ const toolCalls = [];
3416
+ const toolInputBuffers = {};
3417
+ let currentToolId = "";
3418
+ const reader = res.body.getReader();
3419
+ const decoder = new TextDecoder();
3420
+ let buf = "";
3421
+ while (true) {
3422
+ const { done, value } = await reader.read();
3423
+ if (done) break;
3424
+ buf += decoder.decode(value, { stream: true });
3425
+ const lines = buf.split("\n");
3426
+ buf = lines.pop() ?? "";
3427
+ for (const line of lines) {
3428
+ if (!line.startsWith("data: ")) continue;
3429
+ const data = line.slice(6).trim();
3430
+ if (data === "[DONE]" || data === "") continue;
3431
+ let evt;
3432
+ try {
3433
+ evt = JSON.parse(data);
3434
+ } catch {
3435
+ continue;
3436
+ }
3437
+ const type = evt.type;
3438
+ if (type === "message_start") {
3439
+ const usage = evt.message?.usage;
3440
+ inputTokens = usage?.input_tokens ?? 0;
3441
+ modelName = evt.message?.model ?? modelName;
3442
+ } else if (type === "content_block_start") {
3443
+ const block = evt.content_block;
3444
+ if (block?.type === "tool_use") {
3445
+ currentToolId = block.id;
3446
+ toolInputBuffers[currentToolId] = "";
3447
+ toolCalls.push({ id: currentToolId, name: block.name, input: {} });
3448
+ }
3449
+ } else if (type === "content_block_delta") {
3450
+ const delta = evt.delta;
3451
+ if (delta?.type === "text_delta") {
3452
+ const token = delta.text ?? "";
3453
+ textContent += token;
3454
+ if (onToken && token) onToken(token);
3455
+ } else if (delta?.type === "input_json_delta") {
3456
+ toolInputBuffers[currentToolId] = (toolInputBuffers[currentToolId] ?? "") + (delta.partial_json ?? "");
3457
+ }
3458
+ } else if (type === "content_block_stop") {
3459
+ if (currentToolId && toolInputBuffers[currentToolId]) {
3460
+ const tc = toolCalls.find((t) => t.id === currentToolId);
3461
+ if (tc) {
3462
+ try {
3463
+ tc.input = JSON.parse(toolInputBuffers[currentToolId]);
3464
+ } catch {
3465
+ }
3466
+ }
3467
+ }
3468
+ } else if (type === "message_delta") {
3469
+ const usage = evt.usage;
3470
+ outputTokens = usage?.output_tokens ?? 0;
3471
+ const stop = evt.delta?.stop_reason;
3472
+ if (stop === "tool_use") stopReason = "tool_use";
3473
+ else if (stop === "end_turn") stopReason = "end_turn";
3474
+ else if (stop === "max_tokens") stopReason = "max_tokens";
3475
+ }
3476
+ }
3477
+ }
3478
+ return {
3479
+ content: textContent,
3480
+ tool_calls: toolCalls.length > 0 ? toolCalls : null,
3481
+ stop_reason: stopReason,
3482
+ tokens_used: inputTokens + outputTokens,
3483
+ model: modelName
3484
+ };
3485
+ }
3486
+ // ─── OpenAI (also xAI, Gemini) ───────────────────────────────────────────
3487
+ async openai(messages, tools, system, onToken, baseUrl = "https://api.openai.com/v1") {
3488
+ const allMessages = [];
3489
+ const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
3490
+ if (sysContent) allMessages.push({ role: "system", content: sysContent });
3491
+ for (const m of messages.filter((m2) => m2.role !== "system")) {
3492
+ if (m.role === "tool") {
3493
+ allMessages.push({ role: "tool", tool_call_id: m.tool_call_id, content: m.content });
3494
+ } else if (m.role === "assistant" && m.tool_calls?.length) {
3495
+ allMessages.push({
3496
+ role: "assistant",
3497
+ content: m.content || null,
3498
+ tool_calls: m.tool_calls.map((tc) => ({
3499
+ id: tc.id,
3500
+ type: "function",
3501
+ function: { name: tc.name, arguments: JSON.stringify(tc.input) }
3502
+ }))
3503
+ });
3504
+ } else {
3505
+ allMessages.push({ role: m.role, content: m.content });
3506
+ }
3124
3507
  }
3125
- const skill = deps.skillRegistry.get(name);
3126
- if (!skill) {
3127
- return c.json({ error: "Skill not found" }, 404);
3508
+ const body = {
3509
+ model: this.config.model,
3510
+ messages: allMessages,
3511
+ max_tokens: 8192,
3512
+ stream: true,
3513
+ stream_options: { include_usage: true }
3514
+ };
3515
+ if (tools.length > 0) {
3516
+ body.tools = tools.map((t) => ({
3517
+ type: "function",
3518
+ function: { name: t.name, description: t.description, parameters: t.input_schema }
3519
+ }));
3128
3520
  }
3129
- try {
3130
- deps.skillRegistry.removeCustom(name);
3131
- return c.json({ ok: true });
3132
- } catch (err) {
3133
- const message = err instanceof Error ? err.message : String(err);
3134
- return c.json({ error: message }, 500);
3521
+ const res = await fetch(`${this.config.base_url ?? baseUrl}/chat/completions`, {
3522
+ method: "POST",
3523
+ headers: {
3524
+ "Content-Type": "application/json",
3525
+ "Authorization": `Bearer ${this.config.api_key}`
3526
+ },
3527
+ body: JSON.stringify(body)
3528
+ });
3529
+ if (!res.ok) {
3530
+ const err = await res.text();
3531
+ throw new Error(`OpenAI ${res.status}: ${err}`);
3135
3532
  }
3136
- });
3137
- return app;
3138
- }
3139
-
3140
- // packages/daemon/src/HTTPServer.ts
3141
- function findGraphHtml() {
3142
- const candidates = [
3143
- resolve3(dirname2(fileURLToPath(import.meta.url)), "graph.html"),
3144
- // dev (src/)
3145
- resolve3(dirname2(fileURLToPath(import.meta.url)), "..", "graph.html"),
3146
- // bundled (dist/../)
3147
- resolve3(dirname2(fileURLToPath(import.meta.url)), "..", "dist", "graph.html")
3148
- ];
3149
- for (const p of candidates) {
3150
- try {
3151
- readFileSync4(p);
3152
- return p;
3153
- } catch {
3533
+ let textContent = "";
3534
+ let tokensUsed = 0;
3535
+ let modelName = this.config.model;
3536
+ let stopReason = "end_turn";
3537
+ const toolCallMap = {};
3538
+ const reader = res.body.getReader();
3539
+ const decoder = new TextDecoder();
3540
+ let buf = "";
3541
+ while (true) {
3542
+ const { done, value } = await reader.read();
3543
+ if (done) break;
3544
+ buf += decoder.decode(value, { stream: true });
3545
+ const lines = buf.split("\n");
3546
+ buf = lines.pop() ?? "";
3547
+ for (const line of lines) {
3548
+ if (!line.startsWith("data: ")) continue;
3549
+ const data = line.slice(6).trim();
3550
+ if (data === "[DONE]") continue;
3551
+ let evt;
3552
+ try {
3553
+ evt = JSON.parse(data);
3554
+ } catch {
3555
+ continue;
3556
+ }
3557
+ modelName = evt.model ?? modelName;
3558
+ const usage = evt.usage;
3559
+ if (usage?.total_tokens) tokensUsed = usage.total_tokens;
3560
+ const choices = evt.choices;
3561
+ if (!choices?.length) continue;
3562
+ const delta = choices[0].delta;
3563
+ if (!delta) continue;
3564
+ const finish = choices[0].finish_reason;
3565
+ if (finish === "tool_calls") stopReason = "tool_use";
3566
+ else if (finish === "stop") stopReason = "end_turn";
3567
+ const token = delta.content;
3568
+ if (token) {
3569
+ textContent += token;
3570
+ if (onToken) onToken(token);
3571
+ }
3572
+ const toolCallDeltas = delta.tool_calls;
3573
+ if (toolCallDeltas) {
3574
+ for (const tc of toolCallDeltas) {
3575
+ const idx = tc.index;
3576
+ if (!toolCallMap[idx]) {
3577
+ toolCallMap[idx] = { id: "", name: "", args: "" };
3578
+ }
3579
+ const fn = tc.function;
3580
+ if (tc.id) toolCallMap[idx].id = tc.id;
3581
+ if (fn?.name) toolCallMap[idx].name = fn.name;
3582
+ if (fn?.arguments) toolCallMap[idx].args += fn.arguments;
3583
+ }
3584
+ }
3585
+ }
3154
3586
  }
3155
- }
3156
- return candidates[0];
3157
- }
3158
- var GRAPH_HTML_PATH = findGraphHtml();
3159
- var HTTPServer = class {
3160
- app;
3161
- server = null;
3162
- deps;
3163
- constructor(deps) {
3164
- this.deps = deps;
3165
- this.app = new Hono8();
3166
- this.app.route("/api/health", healthRoutes({ getStatus: deps.getStatus }));
3167
- this.app.route("/api/sessions", sessionRoutes({ sessions: deps.sessions }));
3168
- this.app.route("/api/graph", graphRoutes({ graph: deps.graph }));
3169
- this.app.route("/api/entities", entityRoutes({ graph: deps.graph }));
3170
- this.app.route("/api/traces", traceRoutes({ traceStore: deps.traceStore }));
3171
- this.app.route("/api/subagents", subagentRoutes());
3172
- this.app.route("/api/skills", skillRoutes({ skillRegistry: deps.skillRegistry }));
3173
- const serveGraph = (c) => {
3587
+ const toolCalls = Object.values(toolCallMap).filter((tc) => tc.id && tc.name).map((tc) => {
3588
+ let input = {};
3174
3589
  try {
3175
- const html = readFileSync4(GRAPH_HTML_PATH, "utf8");
3176
- return c.html(html);
3590
+ input = JSON.parse(tc.args);
3177
3591
  } catch {
3178
- return c.html("<p>Graph UI not found. Run: pnpm build</p>");
3179
3592
  }
3180
- };
3181
- this.app.get("/", serveGraph);
3182
- this.app.get("/graph", serveGraph);
3183
- }
3184
- start() {
3185
- return new Promise((resolve6) => {
3186
- this.server = serve(
3187
- {
3188
- fetch: this.app.fetch,
3189
- port: this.deps.port,
3190
- hostname: this.deps.host
3191
- },
3192
- () => {
3193
- resolve6();
3194
- }
3195
- );
3593
+ return { id: tc.id, name: tc.name, input };
3196
3594
  });
3595
+ return {
3596
+ content: textContent,
3597
+ tool_calls: toolCalls.length > 0 ? toolCalls : null,
3598
+ stop_reason: stopReason,
3599
+ tokens_used: tokensUsed,
3600
+ model: modelName
3601
+ };
3197
3602
  }
3198
- stop() {
3199
- return new Promise((resolve6, reject) => {
3200
- if (!this.server) {
3201
- resolve6();
3202
- return;
3203
- }
3204
- this.server.close((err) => {
3205
- if (err) reject(err);
3206
- else resolve6();
3207
- });
3603
+ // ─── Ollama (no streaming for simplicity) ────────────────────────────────
3604
+ async ollama(messages, system, onToken) {
3605
+ const baseUrl = this.config.base_url ?? "http://localhost:11434";
3606
+ const allMessages = [];
3607
+ const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
3608
+ if (sysContent) allMessages.push({ role: "system", content: sysContent });
3609
+ allMessages.push(...messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content })));
3610
+ const res = await fetch(`${baseUrl}/api/chat`, {
3611
+ method: "POST",
3612
+ headers: { "Content-Type": "application/json" },
3613
+ body: JSON.stringify({ model: this.config.model, messages: allMessages, stream: false })
3208
3614
  });
3209
- }
3210
- getApp() {
3211
- return this.app;
3615
+ if (!res.ok) throw new Error(`Ollama error ${res.status}`);
3616
+ const data = await res.json();
3617
+ if (onToken) onToken(data.message.content);
3618
+ return { content: data.message.content, tool_calls: null, stop_reason: "end_turn", tokens_used: data.eval_count ?? 0, model: this.config.model };
3212
3619
  }
3213
3620
  };
3214
3621
 
@@ -3227,13 +3634,13 @@ var ZeroAgentDaemon = class {
3227
3634
  startedAt = 0;
3228
3635
  pidFilePath;
3229
3636
  constructor() {
3230
- this.pidFilePath = resolve4(homedir3(), ".0agent", "daemon.pid");
3637
+ this.pidFilePath = resolve5(homedir3(), ".0agent", "daemon.pid");
3231
3638
  }
3232
3639
  async start(opts) {
3233
3640
  this.config = await loadConfig(opts?.config_path);
3234
- const dotDir = resolve4(homedir3(), ".0agent");
3235
- if (!existsSync4(dotDir)) {
3236
- mkdirSync3(dotDir, { recursive: true });
3641
+ const dotDir = resolve5(homedir3(), ".0agent");
3642
+ if (!existsSync5(dotDir)) {
3643
+ mkdirSync4(dotDir, { recursive: true });
3237
3644
  }
3238
3645
  this.adapter = new SQLiteAdapter({ db_path: this.config.graph.db_path });
3239
3646
  this.graph = new KnowledgeGraph(this.adapter);
@@ -3284,7 +3691,7 @@ var ZeroAgentDaemon = class {
3284
3691
  getStatus: () => this.getStatus()
3285
3692
  });
3286
3693
  await this.httpServer.start();
3287
- writeFileSync3(this.pidFilePath, String(process.pid), "utf8");
3694
+ writeFileSync4(this.pidFilePath, String(process.pid), "utf8");
3288
3695
  console.log(
3289
3696
  `[0agent] Daemon started on ${this.config.server.host}:${this.config.server.port} (PID: ${process.pid})`
3290
3697
  );
@@ -3318,7 +3725,7 @@ var ZeroAgentDaemon = class {
3318
3725
  this.graph = null;
3319
3726
  }
3320
3727
  this.adapter = null;
3321
- if (existsSync4(this.pidFilePath)) {
3728
+ if (existsSync5(this.pidFilePath)) {
3322
3729
  try {
3323
3730
  unlinkSync2(this.pidFilePath);
3324
3731
  } catch {
@@ -3348,11 +3755,11 @@ var ZeroAgentDaemon = class {
3348
3755
  };
3349
3756
 
3350
3757
  // packages/daemon/src/start.ts
3351
- import { resolve as resolve5 } from "node:path";
3758
+ import { resolve as resolve6 } from "node:path";
3352
3759
  import { homedir as homedir4 } from "node:os";
3353
- import { existsSync as existsSync5 } from "node:fs";
3354
- var CONFIG_PATH = process.env["ZEROAGENT_CONFIG"] ?? resolve5(homedir4(), ".0agent", "config.yaml");
3355
- if (!existsSync5(CONFIG_PATH)) {
3760
+ import { existsSync as existsSync6 } from "node:fs";
3761
+ var CONFIG_PATH = process.env["ZEROAGENT_CONFIG"] ?? resolve6(homedir4(), ".0agent", "config.yaml");
3762
+ if (!existsSync6(CONFIG_PATH)) {
3356
3763
  console.error(`
3357
3764
  0agent is not initialised.
3358
3765