@beevibe/daemon 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +694 -19
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -408,7 +408,10 @@ async function listFilesRecursive(dir) {
|
|
|
408
408
|
return out;
|
|
409
409
|
}
|
|
410
410
|
// ../core/dist/services/skills/tier-filter.js
|
|
411
|
-
var UNIVERSAL_SKILLS = [
|
|
411
|
+
var UNIVERSAL_SKILLS = [
|
|
412
|
+
"beevibe-pre-task-setup",
|
|
413
|
+
"beevibe-verify-pr"
|
|
414
|
+
];
|
|
412
415
|
var TEAM_ONLY_SKILLS = ["beevibe-team-mesh-negotiation"];
|
|
413
416
|
function tierFilterFor(level) {
|
|
414
417
|
if (level === "ic")
|
|
@@ -876,9 +879,6 @@ class ClaudeCodeRuntime {
|
|
|
876
879
|
args.push("--max-turns", String(maxTurns));
|
|
877
880
|
if (context.resume_session_id)
|
|
878
881
|
args.push("--resume", context.resume_session_id);
|
|
879
|
-
if (context.disallowed_tools?.length) {
|
|
880
|
-
args.push("--disallowedTools", context.disallowed_tools.join(","));
|
|
881
|
-
}
|
|
882
882
|
if (context.system_prompt_append.length > 0) {
|
|
883
883
|
args.push("--append-system-prompt", context.system_prompt_append);
|
|
884
884
|
}
|
|
@@ -1672,6 +1672,9 @@ function createDefaultRuntimeRegistry() {
|
|
|
1672
1672
|
opencode: new OpenCodeRuntime({})
|
|
1673
1673
|
};
|
|
1674
1674
|
}
|
|
1675
|
+
function runtimeMissingError(cli) {
|
|
1676
|
+
return `No runtime registered for dispatch payload type '${cli}'`;
|
|
1677
|
+
}
|
|
1675
1678
|
|
|
1676
1679
|
// src/api-client.ts
|
|
1677
1680
|
import WebSocket from "ws";
|
|
@@ -1732,8 +1735,681 @@ class ApiClient {
|
|
|
1732
1735
|
}
|
|
1733
1736
|
}
|
|
1734
1737
|
|
|
1738
|
+
// ../sandbox/dist/orchestrator.js
|
|
1739
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
1740
|
+
import { mkdir as mkdir2, readFile as readFile2, readdir, writeFile as writeFile2 } from "node:fs/promises";
|
|
1741
|
+
import { dirname as dirname2, join as join7, resolve } from "node:path";
|
|
1742
|
+
import { fileURLToPath } from "node:url";
|
|
1743
|
+
|
|
1744
|
+
// ../sandbox/dist/docker.js
|
|
1745
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1746
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
1747
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
1748
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
1749
|
+
import { join as join6 } from "node:path";
|
|
1750
|
+
var DEFAULT_IMAGE = "python:3.12-slim";
|
|
1751
|
+
var DEFAULT_LIMITS = {
|
|
1752
|
+
cmd_timeout_seconds: 300,
|
|
1753
|
+
cpus: 2,
|
|
1754
|
+
memory: "2g",
|
|
1755
|
+
storage: "4g",
|
|
1756
|
+
network: true
|
|
1757
|
+
};
|
|
1758
|
+
async function createSandbox(opts = {}) {
|
|
1759
|
+
const image = opts.image ?? DEFAULT_IMAGE;
|
|
1760
|
+
const limits = { ...DEFAULT_LIMITS, ...opts.limits ?? {} };
|
|
1761
|
+
const id = generateId(opts.label ?? "bv-sbx");
|
|
1762
|
+
const artifact_dir = await mkdtemp(join6(tmpdir4(), `${id}-artifacts-`));
|
|
1763
|
+
const args = [
|
|
1764
|
+
"run",
|
|
1765
|
+
"--detach",
|
|
1766
|
+
"--name",
|
|
1767
|
+
id,
|
|
1768
|
+
`--cpus=${limits.cpus}`,
|
|
1769
|
+
`--memory=${limits.memory}`,
|
|
1770
|
+
`--storage-opt=size=${limits.storage}`,
|
|
1771
|
+
"--user",
|
|
1772
|
+
"1000:1000",
|
|
1773
|
+
"--tmpfs",
|
|
1774
|
+
"/tmp:rw,size=512m",
|
|
1775
|
+
"-v",
|
|
1776
|
+
`${artifact_dir}:/sandbox/artifacts:rw`,
|
|
1777
|
+
"--workdir",
|
|
1778
|
+
"/sandbox",
|
|
1779
|
+
"--entrypoint",
|
|
1780
|
+
"tail"
|
|
1781
|
+
];
|
|
1782
|
+
if (!limits.network) {
|
|
1783
|
+
args.push("--network=none");
|
|
1784
|
+
}
|
|
1785
|
+
args.push(image, "-f", "/dev/null");
|
|
1786
|
+
const result = await runDocker(args, { timeoutMs: 30000 });
|
|
1787
|
+
if (result.exit_code !== 0) {
|
|
1788
|
+
await rm(artifact_dir, { recursive: true, force: true }).catch(() => {});
|
|
1789
|
+
throw new SandboxError(`Failed to create sandbox: ${result.stderr.trim() || "docker run exited " + result.exit_code}`);
|
|
1790
|
+
}
|
|
1791
|
+
return {
|
|
1792
|
+
id,
|
|
1793
|
+
image,
|
|
1794
|
+
artifact_dir,
|
|
1795
|
+
created_at: new Date
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
async function exec(sandbox, cmd, opts = {}) {
|
|
1799
|
+
const cwd = opts.cwd ?? "/sandbox";
|
|
1800
|
+
const timeoutMs = (opts.timeout_seconds ?? DEFAULT_LIMITS.cmd_timeout_seconds) * 1000;
|
|
1801
|
+
const args = ["exec", "--workdir", cwd];
|
|
1802
|
+
for (const [k, v] of Object.entries(opts.env ?? {})) {
|
|
1803
|
+
args.push("--env", `${k}=${v}`);
|
|
1804
|
+
}
|
|
1805
|
+
args.push(sandbox.id, "sh", "-c", cmd);
|
|
1806
|
+
const startedAt = Date.now();
|
|
1807
|
+
const r = await runDocker(args, { timeoutMs });
|
|
1808
|
+
return {
|
|
1809
|
+
stdout: r.stdout,
|
|
1810
|
+
stderr: r.stderr,
|
|
1811
|
+
exit_code: r.exit_code,
|
|
1812
|
+
timed_out: r.timed_out,
|
|
1813
|
+
duration_seconds: (Date.now() - startedAt) / 1000
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
async function destroySandbox(sandbox) {
|
|
1817
|
+
await runDocker(["rm", "-f", sandbox.id], { timeoutMs: 30000 }).catch(() => {});
|
|
1818
|
+
}
|
|
1819
|
+
async function prepareBaseEnvironment(sandbox) {
|
|
1820
|
+
const r = await runDocker([
|
|
1821
|
+
"exec",
|
|
1822
|
+
"--user",
|
|
1823
|
+
"0",
|
|
1824
|
+
sandbox.id,
|
|
1825
|
+
"sh",
|
|
1826
|
+
"-c",
|
|
1827
|
+
"apt-get update -qq && apt-get install -y -qq --no-install-recommends git curl ca-certificates && rm -rf /var/lib/apt/lists/* && mkdir -p /sandbox && chown -R 1000:1000 /sandbox"
|
|
1828
|
+
], { timeoutMs: 180000 });
|
|
1829
|
+
if (r.exit_code !== 0) {
|
|
1830
|
+
throw new SandboxError(`base prep failed (exit ${r.exit_code}): ${r.stderr.trim().slice(0, 500)}`);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
class SandboxError extends Error {
|
|
1835
|
+
constructor(message) {
|
|
1836
|
+
super(message);
|
|
1837
|
+
this.name = "SandboxError";
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
function runDocker(args, opts) {
|
|
1841
|
+
return new Promise((resolve) => {
|
|
1842
|
+
const proc = spawn2("docker", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1843
|
+
let stdout = "";
|
|
1844
|
+
let stderr = "";
|
|
1845
|
+
let timedOut = false;
|
|
1846
|
+
const timer = setTimeout(() => {
|
|
1847
|
+
timedOut = true;
|
|
1848
|
+
proc.kill("SIGKILL");
|
|
1849
|
+
}, opts.timeoutMs);
|
|
1850
|
+
proc.stdout?.on("data", (c) => {
|
|
1851
|
+
stdout += c.toString("utf8");
|
|
1852
|
+
});
|
|
1853
|
+
proc.stderr?.on("data", (c) => {
|
|
1854
|
+
stderr += c.toString("utf8");
|
|
1855
|
+
});
|
|
1856
|
+
proc.on("error", (err) => {
|
|
1857
|
+
clearTimeout(timer);
|
|
1858
|
+
resolve({
|
|
1859
|
+
stdout,
|
|
1860
|
+
stderr: stderr + `
|
|
1861
|
+
<spawn-error>${err.message}</spawn-error>`,
|
|
1862
|
+
exit_code: -1,
|
|
1863
|
+
timed_out: timedOut
|
|
1864
|
+
});
|
|
1865
|
+
});
|
|
1866
|
+
proc.on("close", (code) => {
|
|
1867
|
+
clearTimeout(timer);
|
|
1868
|
+
resolve({
|
|
1869
|
+
stdout,
|
|
1870
|
+
stderr,
|
|
1871
|
+
exit_code: code ?? -1,
|
|
1872
|
+
timed_out: timedOut
|
|
1873
|
+
});
|
|
1874
|
+
});
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
function generateId(label) {
|
|
1878
|
+
const suffix = randomBytes2(4).toString("hex");
|
|
1879
|
+
const safe = label.toLowerCase().replace(/[^a-z0-9_-]/g, "-").slice(0, 32);
|
|
1880
|
+
return `${safe}-${suffix}`;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
// ../sandbox/dist/orchestrator.js
|
|
1884
|
+
var DEFAULT_PROMPT_HEADER = `You are a Beevibe sandbox child agent running inside a fresh Docker container.
|
|
1885
|
+
|
|
1886
|
+
You have ONLY these five MCP tools to touch the container. They are in your
|
|
1887
|
+
tool list as deferred MCP tools — you MUST load each one via ToolSearch
|
|
1888
|
+
before using it. ToolSearch's "select:" form only accepts ONE tool name per
|
|
1889
|
+
call, so make five separate calls at the very start of your work:
|
|
1890
|
+
|
|
1891
|
+
ToolSearch({ "query": "select:mcp__beevibe-sandbox__sandbox_exec", "max_results": 1 })
|
|
1892
|
+
ToolSearch({ "query": "select:mcp__beevibe-sandbox__sandbox_read_file", "max_results": 1 })
|
|
1893
|
+
ToolSearch({ "query": "select:mcp__beevibe-sandbox__sandbox_write_file", "max_results": 1 })
|
|
1894
|
+
ToolSearch({ "query": "select:mcp__beevibe-sandbox__sandbox_list", "max_results": 1 })
|
|
1895
|
+
ToolSearch({ "query": "select:mcp__beevibe-sandbox__sandbox_export_artifact", "max_results": 1 })
|
|
1896
|
+
|
|
1897
|
+
After those five ToolSearch calls, you may invoke the MCP tools directly:
|
|
1898
|
+
|
|
1899
|
+
mcp__beevibe-sandbox__sandbox_exec(cmd, cwd?, timeout_seconds?)
|
|
1900
|
+
mcp__beevibe-sandbox__sandbox_read_file(path, max_bytes?)
|
|
1901
|
+
mcp__beevibe-sandbox__sandbox_write_file(path, content)
|
|
1902
|
+
mcp__beevibe-sandbox__sandbox_list(path)
|
|
1903
|
+
mcp__beevibe-sandbox__sandbox_export_artifact(sandbox_path, title?)
|
|
1904
|
+
|
|
1905
|
+
You have NO Bash, NO Read, NO Edit, NO Write tool — those will return errors.
|
|
1906
|
+
|
|
1907
|
+
The container has Python 3.12, git, and curl pre-installed. Operate inside
|
|
1908
|
+
/sandbox. Use a project-local venv at /sandbox/venv.
|
|
1909
|
+
|
|
1910
|
+
Your job: use the external repo the user gives you to produce a real artifact
|
|
1911
|
+
for the goal. Plan, install, run, verify, export. You succeed by exporting at
|
|
1912
|
+
least one artifact under /sandbox/artifacts/ via sandbox_export_artifact. Stop
|
|
1913
|
+
as soon as you've exported something useful — don't keep exploring. If you
|
|
1914
|
+
can't, write REASON.txt explaining why and export that.`;
|
|
1915
|
+
function nowIso() {
|
|
1916
|
+
return new Date().toISOString();
|
|
1917
|
+
}
|
|
1918
|
+
var MAX_TRANSCRIPT_EVENTS = 500;
|
|
1919
|
+
var MAX_EVENT_TEXT_BYTES = 4000;
|
|
1920
|
+
function classifyStartupError(err) {
|
|
1921
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
1922
|
+
if (/Cannot connect to the Docker daemon/i.test(raw)) {
|
|
1923
|
+
return "Docker isn't running. Start Docker Desktop and try the run again.";
|
|
1924
|
+
}
|
|
1925
|
+
if (/ENOENT.*docker/i.test(raw)) {
|
|
1926
|
+
return "The `docker` CLI isn't on PATH. Install Docker Desktop (or set DOCKER_HOST).";
|
|
1927
|
+
}
|
|
1928
|
+
if (/no space left on device/i.test(raw)) {
|
|
1929
|
+
return "Docker is out of disk. Prune containers/images or expand Docker Desktop's allotment.";
|
|
1930
|
+
}
|
|
1931
|
+
return raw;
|
|
1932
|
+
}
|
|
1933
|
+
async function runRepoAgent(opts) {
|
|
1934
|
+
const state = {
|
|
1935
|
+
run_id: opts.run_id,
|
|
1936
|
+
status: "starting",
|
|
1937
|
+
repo_url: opts.repo_url,
|
|
1938
|
+
goal: opts.goal,
|
|
1939
|
+
started_at: nowIso(),
|
|
1940
|
+
transcript: [],
|
|
1941
|
+
artifacts: []
|
|
1942
|
+
};
|
|
1943
|
+
const emit = () => opts.on_state?.({ ...state, transcript: state.transcript.slice(), artifacts: state.artifacts.slice() });
|
|
1944
|
+
const log = (kind, text) => {
|
|
1945
|
+
const trimmed = text.length > MAX_EVENT_TEXT_BYTES ? text.slice(0, MAX_EVENT_TEXT_BYTES) + `
|
|
1946
|
+
…[truncated ${text.length - MAX_EVENT_TEXT_BYTES} bytes]…` : text;
|
|
1947
|
+
state.transcript.push({ at: nowIso(), kind, text: trimmed });
|
|
1948
|
+
if (state.transcript.length > MAX_TRANSCRIPT_EVENTS) {
|
|
1949
|
+
const overflow = state.transcript.length - MAX_TRANSCRIPT_EVENTS;
|
|
1950
|
+
state.transcript.splice(1, overflow);
|
|
1951
|
+
const alreadyMarked = state.transcript[1]?.text.startsWith("[log truncated:");
|
|
1952
|
+
if (!alreadyMarked) {
|
|
1953
|
+
state.transcript.splice(1, 0, {
|
|
1954
|
+
at: nowIso(),
|
|
1955
|
+
kind: "log",
|
|
1956
|
+
text: `[log truncated: dropped ${overflow} earlier event${overflow === 1 ? "" : "s"}]`
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
emit();
|
|
1961
|
+
};
|
|
1962
|
+
let sandbox = null;
|
|
1963
|
+
try {
|
|
1964
|
+
log("log", "Creating sandbox container…");
|
|
1965
|
+
state.status = "preparing";
|
|
1966
|
+
emit();
|
|
1967
|
+
try {
|
|
1968
|
+
sandbox = await createSandbox({ label: `bv-run-${opts.run_id}` });
|
|
1969
|
+
} catch (err) {
|
|
1970
|
+
throw new Error(classifyStartupError(err));
|
|
1971
|
+
}
|
|
1972
|
+
state.sandbox_id = sandbox.id;
|
|
1973
|
+
log("log", `Sandbox ${sandbox.id} created (image ${sandbox.image}).`);
|
|
1974
|
+
log("log", "Installing git + curl in the sandbox base image…");
|
|
1975
|
+
await prepareBaseEnvironment(sandbox);
|
|
1976
|
+
log("log", "Base environment ready.");
|
|
1977
|
+
if (opts.input_url) {
|
|
1978
|
+
const filename = opts.input_filename ?? "input.bin";
|
|
1979
|
+
log("log", `Fetching input into /sandbox/inputs/${filename}…`);
|
|
1980
|
+
const r = await exec(sandbox, `mkdir -p /sandbox/inputs && curl -fsSL ${shellQuote(opts.input_url)} -o /sandbox/inputs/${shellQuote(filename)}`, { timeout_seconds: 120 });
|
|
1981
|
+
if (r.exit_code !== 0) {
|
|
1982
|
+
throw new Error(`input fetch failed: ${r.stderr.trim().slice(0, 400)}`);
|
|
1983
|
+
}
|
|
1984
|
+
log("log", "Input file ready.");
|
|
1985
|
+
}
|
|
1986
|
+
const mcpServerCommand = opts.mcp_server_command ?? defaultMcpServerCommand();
|
|
1987
|
+
const mcpConfigPath = join7(sandbox.artifact_dir, "mcp-config.json");
|
|
1988
|
+
const mcpConfig = {
|
|
1989
|
+
mcpServers: {
|
|
1990
|
+
"beevibe-sandbox": {
|
|
1991
|
+
command: mcpServerCommand.command,
|
|
1992
|
+
args: mcpServerCommand.args,
|
|
1993
|
+
env: {
|
|
1994
|
+
BEEVIBE_SANDBOX_ID: sandbox.id,
|
|
1995
|
+
BEEVIBE_SANDBOX_ARTIFACTS: sandbox.artifact_dir
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
await writeFile2(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf8");
|
|
2001
|
+
log("log", `MCP config written: ${mcpConfigPath}`);
|
|
2002
|
+
const userPrompt = buildUserPrompt(opts);
|
|
2003
|
+
const systemPromptAppend = DEFAULT_PROMPT_HEADER;
|
|
2004
|
+
state.status = "running";
|
|
2005
|
+
log("log", "Spawning child claude session…");
|
|
2006
|
+
emit();
|
|
2007
|
+
const claudeResult = await runClaude({
|
|
2008
|
+
claudeBin: opts.claude_bin ?? "claude",
|
|
2009
|
+
mcpConfigPath,
|
|
2010
|
+
systemPromptAppend,
|
|
2011
|
+
userPrompt,
|
|
2012
|
+
maxBudgetUsd: opts.max_budget_usd ?? 2,
|
|
2013
|
+
timeoutSeconds: opts.max_runtime_seconds ?? 600,
|
|
2014
|
+
onTranscript: (kind, text) => log(kind, text)
|
|
2015
|
+
});
|
|
2016
|
+
if (claudeResult.exit_code !== 0 && claudeResult.exit_code !== null) {
|
|
2017
|
+
const tail = claudeResult.stderr.slice(-500);
|
|
2018
|
+
log("error", `Child claude exited with code ${claudeResult.exit_code}: ${tail}`);
|
|
2019
|
+
state.status = claudeResult.timed_out ? "blocked" : "failed";
|
|
2020
|
+
state.error = claudeResult.timed_out ? `Run hit the ${opts.max_runtime_seconds ?? 600}s wall-clock budget — agent didn't finish in time.` : `Claude exited ${claudeResult.exit_code}.${tail ? " " + tail.slice(-200) : ""}`;
|
|
2021
|
+
state.finished_at = nowIso();
|
|
2022
|
+
emit();
|
|
2023
|
+
return state;
|
|
2024
|
+
}
|
|
2025
|
+
log("log", "Child claude exited cleanly. Collecting artifacts…");
|
|
2026
|
+
state.artifacts = await collectArtifacts(sandbox);
|
|
2027
|
+
if (state.artifacts.length === 0) {
|
|
2028
|
+
state.status = "blocked";
|
|
2029
|
+
state.error = "agent produced no artifacts";
|
|
2030
|
+
} else {
|
|
2031
|
+
state.status = "succeeded";
|
|
2032
|
+
}
|
|
2033
|
+
state.finished_at = nowIso();
|
|
2034
|
+
emit();
|
|
2035
|
+
return state;
|
|
2036
|
+
} catch (err) {
|
|
2037
|
+
log("error", err instanceof Error ? err.message : String(err));
|
|
2038
|
+
state.status = "failed";
|
|
2039
|
+
state.error = err instanceof Error ? err.message : String(err);
|
|
2040
|
+
state.finished_at = nowIso();
|
|
2041
|
+
emit();
|
|
2042
|
+
return state;
|
|
2043
|
+
} finally {
|
|
2044
|
+
if (sandbox) {
|
|
2045
|
+
try {
|
|
2046
|
+
log("log", `Destroying sandbox ${sandbox.id}…`);
|
|
2047
|
+
await destroySandbox(sandbox);
|
|
2048
|
+
} catch (err) {
|
|
2049
|
+
log("log", `Sandbox cleanup note: ${err instanceof Error ? err.message : String(err)}. Run with \`docker ps -a --filter name=bv-run-\` to inspect.`);
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
function buildUserPrompt(opts) {
|
|
2055
|
+
const lines = [
|
|
2056
|
+
`Goal: ${opts.goal}`,
|
|
2057
|
+
`Repo: ${opts.repo_url}`
|
|
2058
|
+
];
|
|
2059
|
+
if (opts.input_url) {
|
|
2060
|
+
lines.push(`Input file (pre-fetched): /sandbox/inputs/${opts.input_filename ?? "input.bin"}`);
|
|
2061
|
+
}
|
|
2062
|
+
lines.push("");
|
|
2063
|
+
lines.push("Work inside /sandbox. Clone the repo to /sandbox/repo. Install in a venv. ");
|
|
2064
|
+
lines.push("Produce at least one artifact under /sandbox/artifacts/, then call ");
|
|
2065
|
+
lines.push("sandbox_export_artifact() on each one with a short, human-readable title. ");
|
|
2066
|
+
lines.push("Stop as soon as you've exported a useful artifact — don't keep exploring.");
|
|
2067
|
+
return lines.join(`
|
|
2068
|
+
`);
|
|
2069
|
+
}
|
|
2070
|
+
var ALLOWED_TOOLS = [
|
|
2071
|
+
"mcp__beevibe-sandbox__sandbox_exec",
|
|
2072
|
+
"mcp__beevibe-sandbox__sandbox_read_file",
|
|
2073
|
+
"mcp__beevibe-sandbox__sandbox_write_file",
|
|
2074
|
+
"mcp__beevibe-sandbox__sandbox_list",
|
|
2075
|
+
"mcp__beevibe-sandbox__sandbox_export_artifact"
|
|
2076
|
+
];
|
|
2077
|
+
var DISALLOWED_TOOLS = ["Bash", "Read", "Edit", "Write", "BashOutput", "KillBash"];
|
|
2078
|
+
function runClaude(args) {
|
|
2079
|
+
return new Promise((resolve2) => {
|
|
2080
|
+
const cliArgs = [
|
|
2081
|
+
"--print",
|
|
2082
|
+
"--mcp-config",
|
|
2083
|
+
args.mcpConfigPath,
|
|
2084
|
+
"--allowed-tools",
|
|
2085
|
+
ALLOWED_TOOLS.join(","),
|
|
2086
|
+
"--disallowed-tools",
|
|
2087
|
+
DISALLOWED_TOOLS.join(","),
|
|
2088
|
+
"--append-system-prompt",
|
|
2089
|
+
args.systemPromptAppend,
|
|
2090
|
+
"--max-budget-usd",
|
|
2091
|
+
String(args.maxBudgetUsd),
|
|
2092
|
+
"--output-format",
|
|
2093
|
+
"stream-json",
|
|
2094
|
+
"--verbose"
|
|
2095
|
+
];
|
|
2096
|
+
const proc = spawn3(args.claudeBin, cliArgs, {
|
|
2097
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2098
|
+
env: { ...process.env },
|
|
2099
|
+
detached: true
|
|
2100
|
+
});
|
|
2101
|
+
proc.unref();
|
|
2102
|
+
let stdout = "";
|
|
2103
|
+
let stderr = "";
|
|
2104
|
+
let timedOut = false;
|
|
2105
|
+
let stdoutBuffer = "";
|
|
2106
|
+
const timer = setTimeout(() => {
|
|
2107
|
+
timedOut = true;
|
|
2108
|
+
proc.kill("SIGTERM");
|
|
2109
|
+
setTimeout(() => proc.kill("SIGKILL"), 5000);
|
|
2110
|
+
}, args.timeoutSeconds * 1000);
|
|
2111
|
+
proc.stdout.on("data", (chunk) => {
|
|
2112
|
+
const s = chunk.toString("utf8");
|
|
2113
|
+
stdout += s;
|
|
2114
|
+
stdoutBuffer += s;
|
|
2115
|
+
let nl;
|
|
2116
|
+
while ((nl = stdoutBuffer.indexOf(`
|
|
2117
|
+
`)) !== -1) {
|
|
2118
|
+
const line = stdoutBuffer.slice(0, nl);
|
|
2119
|
+
stdoutBuffer = stdoutBuffer.slice(nl + 1);
|
|
2120
|
+
if (line.trim().length === 0)
|
|
2121
|
+
continue;
|
|
2122
|
+
try {
|
|
2123
|
+
const evt = JSON.parse(line);
|
|
2124
|
+
if (evt && typeof evt === "object" && evt.type === "system" && evt.subtype === "init") {
|
|
2125
|
+
const init = evt;
|
|
2126
|
+
const servers = init.mcp_servers;
|
|
2127
|
+
if (servers) {
|
|
2128
|
+
for (const sv of servers) {
|
|
2129
|
+
args.onTranscript("log", `mcp server ${sv.name}: ${sv.status}`);
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
const tools = init.tools;
|
|
2133
|
+
const mcpTools = (tools ?? []).filter((t) => t.startsWith("mcp__beevibe-sandbox__"));
|
|
2134
|
+
args.onTranscript("log", `mcp tools exposed: ${mcpTools.length ? mcpTools.join(", ") : "none"}`);
|
|
2135
|
+
}
|
|
2136
|
+
handleStreamEvent(evt, args.onTranscript);
|
|
2137
|
+
} catch {}
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
proc.stderr.on("data", (chunk) => {
|
|
2141
|
+
stderr += chunk.toString("utf8");
|
|
2142
|
+
});
|
|
2143
|
+
proc.on("error", (err) => {
|
|
2144
|
+
clearTimeout(timer);
|
|
2145
|
+
const friendly = /ENOENT/i.test(err.message) ? `Claude CLI not found at ${args.claudeBin}. Set BEEVIBE_CLAUDE_BIN to the binary path.` : `claude spawn error: ${err.message}`;
|
|
2146
|
+
args.onTranscript("error", friendly);
|
|
2147
|
+
resolve2({ exit_code: -1, stdout, stderr, timed_out: timedOut });
|
|
2148
|
+
});
|
|
2149
|
+
proc.on("close", (code) => {
|
|
2150
|
+
clearTimeout(timer);
|
|
2151
|
+
if (code !== 0 && code !== null) {
|
|
2152
|
+
const tail = stderr.slice(-800).trim();
|
|
2153
|
+
if (tail) {
|
|
2154
|
+
args.onTranscript("error", `claude stderr tail: ${tail}`);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
resolve2({ exit_code: code, stdout, stderr, timed_out: timedOut });
|
|
2158
|
+
});
|
|
2159
|
+
proc.stdin.write(args.userPrompt);
|
|
2160
|
+
proc.stdin.end();
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
function handleStreamEvent(evt, emit) {
|
|
2164
|
+
if (!evt || typeof evt !== "object")
|
|
2165
|
+
return;
|
|
2166
|
+
const e = evt;
|
|
2167
|
+
const t = e.type;
|
|
2168
|
+
if (t === "assistant" || t === "assistant_message") {
|
|
2169
|
+
const message = e.message;
|
|
2170
|
+
if (message && Array.isArray(message.content)) {
|
|
2171
|
+
for (const item of message.content) {
|
|
2172
|
+
if (!item || typeof item !== "object")
|
|
2173
|
+
continue;
|
|
2174
|
+
const it = item;
|
|
2175
|
+
if (it.type === "text" && typeof it.text === "string") {
|
|
2176
|
+
emit("agent", it.text);
|
|
2177
|
+
} else if (it.type === "tool_use") {
|
|
2178
|
+
const name = String(it.name ?? "unknown");
|
|
2179
|
+
const input = it.input ? compactJson(it.input) : "";
|
|
2180
|
+
emit("tool_call", `${name}(${input})`);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
} else if (typeof e.content === "string") {
|
|
2184
|
+
emit("agent", e.content);
|
|
2185
|
+
}
|
|
2186
|
+
} else if (t === "user" || t === "user_message") {
|
|
2187
|
+
const message = e.message;
|
|
2188
|
+
if (message && Array.isArray(message.content)) {
|
|
2189
|
+
for (const item of message.content) {
|
|
2190
|
+
if (!item || typeof item !== "object")
|
|
2191
|
+
continue;
|
|
2192
|
+
const it = item;
|
|
2193
|
+
if (it.type === "tool_result") {
|
|
2194
|
+
const content = it.content;
|
|
2195
|
+
let text;
|
|
2196
|
+
if (typeof content === "string") {
|
|
2197
|
+
text = content;
|
|
2198
|
+
} else if (Array.isArray(content)) {
|
|
2199
|
+
text = content.map((c) => c && typeof c === "object" && typeof c.text === "string" ? c.text : "").filter(Boolean).join(" ");
|
|
2200
|
+
} else {
|
|
2201
|
+
text = JSON.stringify(content ?? null);
|
|
2202
|
+
}
|
|
2203
|
+
const isErr = it.is_error === true;
|
|
2204
|
+
emit(isErr ? "error" : "tool_call", `→ ${text.slice(0, 300)}${text.length > 300 ? "…" : ""}`);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
} else if (t === "result" && typeof e.result === "string") {
|
|
2209
|
+
emit("agent", e.result);
|
|
2210
|
+
} else if (t === "error") {
|
|
2211
|
+
emit("error", typeof e.message === "string" ? e.message : "claude error");
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
function compactJson(v) {
|
|
2215
|
+
try {
|
|
2216
|
+
const s = JSON.stringify(v);
|
|
2217
|
+
return s.length > 200 ? s.slice(0, 200) + "…" : s;
|
|
2218
|
+
} catch {
|
|
2219
|
+
return "?";
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
async function collectArtifacts(sandbox) {
|
|
2223
|
+
const out = [];
|
|
2224
|
+
await mkdir2(sandbox.artifact_dir, { recursive: true });
|
|
2225
|
+
const entries = await readdir(sandbox.artifact_dir);
|
|
2226
|
+
const sidecars = new Map;
|
|
2227
|
+
for (const e of entries) {
|
|
2228
|
+
if (e.endsWith(".meta.json")) {
|
|
2229
|
+
try {
|
|
2230
|
+
const raw = await readFile2(join7(sandbox.artifact_dir, e), "utf8");
|
|
2231
|
+
sidecars.set(e.replace(/\.meta\.json$/, ""), JSON.parse(raw));
|
|
2232
|
+
} catch {}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
for (const e of entries) {
|
|
2236
|
+
if (e.endsWith(".meta.json") || e === "mcp-config.json")
|
|
2237
|
+
continue;
|
|
2238
|
+
const hostPath = join7(sandbox.artifact_dir, e);
|
|
2239
|
+
const stat = await readFile2(hostPath).then((b) => ({ size: b.byteLength }), () => null);
|
|
2240
|
+
if (!stat)
|
|
2241
|
+
continue;
|
|
2242
|
+
const meta = sidecars.get(e);
|
|
2243
|
+
out.push({
|
|
2244
|
+
filename: e,
|
|
2245
|
+
title: typeof meta?.title === "string" && meta.title || e.replace(/\.[^.]+$/, ""),
|
|
2246
|
+
size_bytes: stat.size,
|
|
2247
|
+
host_path: hostPath,
|
|
2248
|
+
sandbox_path: typeof meta?.sandbox_path === "string" && meta.sandbox_path || undefined
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
return out;
|
|
2252
|
+
}
|
|
2253
|
+
function defaultMcpServerCommand() {
|
|
2254
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2255
|
+
const isTsxRun = here.endsWith("/src");
|
|
2256
|
+
const mcpServerPath = resolve(here, isTsxRun ? "./mcp-server.ts" : "./mcp-server.js");
|
|
2257
|
+
return isTsxRun ? { command: "npx", args: ["--no-install", "tsx", mcpServerPath] } : { command: "node", args: ["--enable-source-maps", mcpServerPath] };
|
|
2258
|
+
}
|
|
2259
|
+
function shellQuote(s) {
|
|
2260
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
// src/repo-runs.ts
|
|
2264
|
+
var CLAUDE_BIN = process.env.BEEVIBE_CLAUDE_BIN ?? "claude";
|
|
2265
|
+
async function runRepoDispatch(deps, payload, abortSignal) {
|
|
2266
|
+
const rr = payload.run_repo;
|
|
2267
|
+
if (!rr) {
|
|
2268
|
+
throw new Error("run_repo dispatch missing payload.run_repo");
|
|
2269
|
+
}
|
|
2270
|
+
console.log(`[daemon/repo-run] sess=${payload.session_id} repo_run=${rr.repo_run_id} repo=${rr.repo_url}`);
|
|
2271
|
+
const buffer = [];
|
|
2272
|
+
let flushTimer;
|
|
2273
|
+
const flush = async () => {
|
|
2274
|
+
if (buffer.length === 0)
|
|
2275
|
+
return;
|
|
2276
|
+
const events = buffer.splice(0);
|
|
2277
|
+
try {
|
|
2278
|
+
await deps.api.post("/runtime/events", { events });
|
|
2279
|
+
} catch (err) {
|
|
2280
|
+
console.warn("[daemon/repo-run] /runtime/events POST failed:", err instanceof Error ? err.message : String(err));
|
|
2281
|
+
}
|
|
2282
|
+
};
|
|
2283
|
+
const scheduleFlush = () => {
|
|
2284
|
+
if (flushTimer)
|
|
2285
|
+
return;
|
|
2286
|
+
flushTimer = setTimeout(() => {
|
|
2287
|
+
flushTimer = undefined;
|
|
2288
|
+
flush();
|
|
2289
|
+
}, 250);
|
|
2290
|
+
};
|
|
2291
|
+
let pushedUpTo = 0;
|
|
2292
|
+
const pushNew = (transcript) => {
|
|
2293
|
+
for (let i = pushedUpTo;i < transcript.length; i++) {
|
|
2294
|
+
const ev = transcript[i];
|
|
2295
|
+
if (!ev)
|
|
2296
|
+
continue;
|
|
2297
|
+
buffer.push({
|
|
2298
|
+
session_id: payload.session_id,
|
|
2299
|
+
kind: mapKind(ev.kind),
|
|
2300
|
+
content: ev.text
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
pushedUpTo = transcript.length;
|
|
2304
|
+
if (buffer.length >= 16)
|
|
2305
|
+
flush();
|
|
2306
|
+
else
|
|
2307
|
+
scheduleFlush();
|
|
2308
|
+
};
|
|
2309
|
+
const installLines = [];
|
|
2310
|
+
let invocation;
|
|
2311
|
+
const noteCommandFromToolCall = (text) => {
|
|
2312
|
+
const m = text.match(/sandbox_exec\(\{?"?cmd"?:?\s*"([^"]+)"/);
|
|
2313
|
+
if (!m)
|
|
2314
|
+
return;
|
|
2315
|
+
const cmd = m[1] ?? "";
|
|
2316
|
+
if (!cmd)
|
|
2317
|
+
return;
|
|
2318
|
+
if (isInstallCommand(cmd))
|
|
2319
|
+
installLines.push(cmd);
|
|
2320
|
+
else
|
|
2321
|
+
invocation = cmd;
|
|
2322
|
+
};
|
|
2323
|
+
const result = await runRepoAgent({
|
|
2324
|
+
run_id: rr.repo_run_id,
|
|
2325
|
+
repo_url: rr.repo_url,
|
|
2326
|
+
goal: rr.goal,
|
|
2327
|
+
input_url: rr.input_url,
|
|
2328
|
+
input_filename: rr.input_filename,
|
|
2329
|
+
claude_bin: CLAUDE_BIN,
|
|
2330
|
+
max_runtime_seconds: (rr.limits?.wall_clock_minutes ?? 20) * 60,
|
|
2331
|
+
on_state: (s) => {
|
|
2332
|
+
pushNew(s.transcript);
|
|
2333
|
+
for (let i = pushedUpTo - (s.transcript.length - 0);i < s.transcript.length; i++) {
|
|
2334
|
+
if (i < 0)
|
|
2335
|
+
continue;
|
|
2336
|
+
const ev = s.transcript[i];
|
|
2337
|
+
if (ev?.kind === "tool_call")
|
|
2338
|
+
noteCommandFromToolCall(ev.text);
|
|
2339
|
+
}
|
|
2340
|
+
if (abortSignal?.aborted) {
|
|
2341
|
+
buffer.push({
|
|
2342
|
+
session_id: payload.session_id,
|
|
2343
|
+
kind: "summary",
|
|
2344
|
+
content: "[run cancelled by user]"
|
|
2345
|
+
});
|
|
2346
|
+
flush();
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
});
|
|
2350
|
+
if (flushTimer) {
|
|
2351
|
+
clearTimeout(flushTimer);
|
|
2352
|
+
flushTimer = undefined;
|
|
2353
|
+
}
|
|
2354
|
+
await flush();
|
|
2355
|
+
const status = result.status === "succeeded" ? "succeeded" : result.status === "blocked" ? "failed" : result.status === "failed" ? "failed" : "failed";
|
|
2356
|
+
const artifacts = result.artifacts.map((a) => ({
|
|
2357
|
+
filename: a.filename,
|
|
2358
|
+
title: a.title,
|
|
2359
|
+
size_bytes: a.size_bytes,
|
|
2360
|
+
host_path: a.host_path,
|
|
2361
|
+
sandbox_path: a.sandbox_path
|
|
2362
|
+
}));
|
|
2363
|
+
const done = {
|
|
2364
|
+
session_id: payload.session_id,
|
|
2365
|
+
status,
|
|
2366
|
+
result_summary: result.status === "succeeded" ? `Exported ${artifacts.length} artifact${artifacts.length === 1 ? "" : "s"}.` : result.error ?? "Run did not produce an artifact.",
|
|
2367
|
+
error: result.error,
|
|
2368
|
+
run_repo: {
|
|
2369
|
+
repo_run_id: rr.repo_run_id,
|
|
2370
|
+
install_log: installLines.length ? installLines.join(`
|
|
2371
|
+
`) : undefined,
|
|
2372
|
+
invocation,
|
|
2373
|
+
artifacts
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
if (status === "succeeded") {
|
|
2377
|
+
console.log(`[daemon/repo-run] sess=${payload.session_id} succeeded artifacts=${artifacts.length}`);
|
|
2378
|
+
} else {
|
|
2379
|
+
console.error(`[daemon/repo-run] sess=${payload.session_id} status=${status}` + (result.error ? `
|
|
2380
|
+
error:
|
|
2381
|
+
${result.error.split(`
|
|
2382
|
+
`).join(`
|
|
2383
|
+
`)}` : ""));
|
|
2384
|
+
}
|
|
2385
|
+
try {
|
|
2386
|
+
await deps.api.post("/runtime/done", done);
|
|
2387
|
+
} catch (err) {
|
|
2388
|
+
console.error("[daemon/repo-run] /runtime/done POST failed:", err instanceof Error ? err.message : String(err));
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
function mapKind(kind) {
|
|
2392
|
+
switch (kind) {
|
|
2393
|
+
case "agent":
|
|
2394
|
+
return "agent";
|
|
2395
|
+
case "tool_call":
|
|
2396
|
+
return "tool_call";
|
|
2397
|
+
case "log":
|
|
2398
|
+
return "summary";
|
|
2399
|
+
case "error":
|
|
2400
|
+
return "tool_result";
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
function isInstallCommand(cmd) {
|
|
2404
|
+
return /^(pip\s|pip3\s|apt-get\s|apt\s|brew\s|npm\s+(install|i)|yarn\s+(add|install)|pnpm\s+(add|install)|git\s+clone)/.test(cmd.trim());
|
|
2405
|
+
}
|
|
2406
|
+
|
|
1735
2407
|
// src/spawner.ts
|
|
1736
2408
|
async function runDispatch(deps, payload, abortSignal) {
|
|
2409
|
+
if (payload.type === "run_repo") {
|
|
2410
|
+
await runRepoDispatch({ api: deps.api }, payload, abortSignal);
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
1737
2413
|
const syntheticAgent = {
|
|
1738
2414
|
id: payload.agent_id,
|
|
1739
2415
|
api_key: payload.agent_api_key,
|
|
@@ -1745,7 +2421,7 @@ async function runDispatch(deps, payload, abortSignal) {
|
|
|
1745
2421
|
const registry = deps.runtimeRegistry ?? createDefaultRuntimeRegistry();
|
|
1746
2422
|
const runtime3 = registry[payload.runtime_type];
|
|
1747
2423
|
if (!runtime3) {
|
|
1748
|
-
throw new Error(
|
|
2424
|
+
throw new Error(runtimeMissingError(payload.runtime_type));
|
|
1749
2425
|
}
|
|
1750
2426
|
const buffer = [];
|
|
1751
2427
|
let flushTimer;
|
|
@@ -1788,7 +2464,6 @@ async function runDispatch(deps, payload, abortSignal) {
|
|
|
1788
2464
|
system_prompt_append: payload.system_prompt_append,
|
|
1789
2465
|
model: payload.model,
|
|
1790
2466
|
max_turns: payload.max_turns,
|
|
1791
|
-
disallowed_tools: payload.disallowed_tools,
|
|
1792
2467
|
env: payload.env,
|
|
1793
2468
|
resume_session_id: payload.resume_session_id,
|
|
1794
2469
|
abort_signal: abortSignal,
|
|
@@ -1964,14 +2639,14 @@ class Claimer {
|
|
|
1964
2639
|
// src/skills-cache.ts
|
|
1965
2640
|
import { promises as fs2 } from "node:fs";
|
|
1966
2641
|
import { homedir as homedir3 } from "node:os";
|
|
1967
|
-
import { join as
|
|
2642
|
+
import { join as join8 } from "node:path";
|
|
1968
2643
|
function skillsCacheDir() {
|
|
1969
|
-
return
|
|
2644
|
+
return join8(homedir3(), ".beevibe", "skills");
|
|
1970
2645
|
}
|
|
1971
2646
|
var VERSION_FILE = ".version";
|
|
1972
2647
|
async function readCachedVersion() {
|
|
1973
2648
|
try {
|
|
1974
|
-
return (await fs2.readFile(
|
|
2649
|
+
return (await fs2.readFile(join8(skillsCacheDir(), VERSION_FILE), "utf8")).trim();
|
|
1975
2650
|
} catch {
|
|
1976
2651
|
return;
|
|
1977
2652
|
}
|
|
@@ -1992,19 +2667,19 @@ async function syncSkillsCache(api) {
|
|
|
1992
2667
|
if (!dirent.isDirectory())
|
|
1993
2668
|
continue;
|
|
1994
2669
|
if (dirent.name === "beevibe" || dirent.name.startsWith("beevibe-")) {
|
|
1995
|
-
await fs2.rm(
|
|
2670
|
+
await fs2.rm(join8(cache, dirent.name), { recursive: true, force: true });
|
|
1996
2671
|
}
|
|
1997
2672
|
}
|
|
1998
2673
|
for (const skill of res.skills) {
|
|
1999
|
-
const skillDir =
|
|
2674
|
+
const skillDir = join8(cache, skill.name);
|
|
2000
2675
|
await fs2.mkdir(skillDir, { recursive: true, mode: 448 });
|
|
2001
2676
|
for (const file of skill.files) {
|
|
2002
|
-
const filePath =
|
|
2003
|
-
await fs2.mkdir(
|
|
2677
|
+
const filePath = join8(skillDir, file.path);
|
|
2678
|
+
await fs2.mkdir(join8(filePath, ".."), { recursive: true });
|
|
2004
2679
|
await fs2.writeFile(filePath, file.content, { mode: 384 });
|
|
2005
2680
|
}
|
|
2006
2681
|
}
|
|
2007
|
-
await fs2.writeFile(
|
|
2682
|
+
await fs2.writeFile(join8(cache, VERSION_FILE), res.version, { mode: 384 });
|
|
2008
2683
|
return cache;
|
|
2009
2684
|
}
|
|
2010
2685
|
|
|
@@ -2137,8 +2812,8 @@ async function runSync() {
|
|
|
2137
2812
|
// src/update.ts
|
|
2138
2813
|
import { createHash } from "node:crypto";
|
|
2139
2814
|
import { createWriteStream, mkdtempSync, rmSync as rmSync2, chmodSync, renameSync } from "node:fs";
|
|
2140
|
-
import { tmpdir as
|
|
2141
|
-
import { join as
|
|
2815
|
+
import { tmpdir as tmpdir5 } from "node:os";
|
|
2816
|
+
import { join as join9 } from "node:path";
|
|
2142
2817
|
import { Readable } from "node:stream";
|
|
2143
2818
|
import { pipeline } from "node:stream/promises";
|
|
2144
2819
|
import { createInterface } from "node:readline/promises";
|
|
@@ -2152,7 +2827,7 @@ var PLATFORM_ASSETS = {
|
|
|
2152
2827
|
"linux-arm64": "beevibe-daemon-linux-arm64"
|
|
2153
2828
|
};
|
|
2154
2829
|
function currentVersion() {
|
|
2155
|
-
return "0.1.
|
|
2830
|
+
return "0.1.5";
|
|
2156
2831
|
}
|
|
2157
2832
|
function isCompiledBinary() {
|
|
2158
2833
|
if (!process.versions.bun)
|
|
@@ -2265,8 +2940,8 @@ async function runUpdate(opts = {}) {
|
|
|
2265
2940
|
return;
|
|
2266
2941
|
}
|
|
2267
2942
|
}
|
|
2268
|
-
const stagingDir = mkdtempSync(
|
|
2269
|
-
const stagingPath =
|
|
2943
|
+
const stagingDir = mkdtempSync(join9(tmpdir5(), "beevibe-daemon-update-"));
|
|
2944
|
+
const stagingPath = join9(stagingDir, asset);
|
|
2270
2945
|
try {
|
|
2271
2946
|
console.log(`Downloading ${asset}…`);
|
|
2272
2947
|
const downloadUrl = `${DOWNLOAD_BASE}/${latest}/${asset}`;
|
package/package.json
CHANGED