@matthias-hausberger/beige 0.2.0-beta1 → 0.2.0-beta2
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/package.json +2 -1
- package/sandbox/Dockerfile +28 -0
- package/sandbox/tool-client.ts +95 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matthias-hausberger/beige",
|
|
3
|
-
"version": "0.2.0-
|
|
3
|
+
"version": "0.2.0-beta2",
|
|
4
4
|
"description": "Secure sandboxed agent system",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
22
|
"tools",
|
|
23
|
+
"sandbox",
|
|
23
24
|
"config.schema.json"
|
|
24
25
|
],
|
|
25
26
|
"dependencies": {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
FROM denoland/deno:2.2.3
|
|
2
|
+
|
|
3
|
+
# Install common utilities
|
|
4
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
5
|
+
curl \
|
|
6
|
+
jq \
|
|
7
|
+
git \
|
|
8
|
+
ca-certificates \
|
|
9
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
10
|
+
|
|
11
|
+
# Create workspace directory
|
|
12
|
+
RUN mkdir -p /workspace /tools/bin /tools/packages /beige
|
|
13
|
+
|
|
14
|
+
# Copy tool-client source
|
|
15
|
+
COPY tool-client.ts /beige/tool-client.ts
|
|
16
|
+
|
|
17
|
+
# Create a wrapper script that runs tool-client via deno
|
|
18
|
+
# --allow-read: read the socket file path
|
|
19
|
+
# --allow-write: needed for some Deno versions with Unix sockets
|
|
20
|
+
# --allow-env: environment variables
|
|
21
|
+
# --unstable-net: Unix domain socket support (needed for some Deno 2.x builds)
|
|
22
|
+
RUN echo '#!/bin/sh' > /beige/tool-client && \
|
|
23
|
+
echo 'exec deno run --allow-read --allow-write --allow-net --allow-env --unstable-net /beige/tool-client.ts "$@"' >> /beige/tool-client && \
|
|
24
|
+
chmod +x /beige/tool-client
|
|
25
|
+
|
|
26
|
+
WORKDIR /workspace
|
|
27
|
+
|
|
28
|
+
# No CMD — container is started with "sleep infinity" by the gateway
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool client — runs INSIDE the sandbox (Deno).
|
|
3
|
+
* Connects to the gateway via Unix domain socket and sends tool requests.
|
|
4
|
+
*
|
|
5
|
+
* Usage: tool-client <tool-name> [args...]
|
|
6
|
+
*
|
|
7
|
+
* Mounted read-only into the sandbox at /beige/tool-client.ts.
|
|
8
|
+
* Run via the wrapper: /beige/tool-client (which invokes deno run ...)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const SOCKET_PATH = "/beige/gateway.sock";
|
|
12
|
+
|
|
13
|
+
const toolName = Deno.args[0];
|
|
14
|
+
const args = Deno.args.slice(1);
|
|
15
|
+
|
|
16
|
+
if (!toolName) {
|
|
17
|
+
console.error("Usage: tool-client <tool-name> [args...]");
|
|
18
|
+
Deno.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildSessionContext(): Record<string, string> | undefined {
|
|
22
|
+
const sessionKey = Deno.env.get("BEIGE_SESSION_KEY");
|
|
23
|
+
const channel = Deno.env.get("BEIGE_CHANNEL");
|
|
24
|
+
const agentName = Deno.env.get("BEIGE_AGENT_NAME");
|
|
25
|
+
const chatId = Deno.env.get("BEIGE_CHAT_ID");
|
|
26
|
+
const threadId = Deno.env.get("BEIGE_THREAD_ID");
|
|
27
|
+
|
|
28
|
+
if (!sessionKey || !channel) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const ctx: Record<string, string> = { sessionKey, channel };
|
|
33
|
+
if (agentName) ctx.agentName = agentName;
|
|
34
|
+
if (chatId) ctx.chatId = chatId;
|
|
35
|
+
if (threadId) ctx.threadId = threadId;
|
|
36
|
+
return ctx;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const sessionContext = buildSessionContext();
|
|
40
|
+
|
|
41
|
+
const request: Record<string, unknown> = {
|
|
42
|
+
type: "tool_request",
|
|
43
|
+
tool: toolName,
|
|
44
|
+
args,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
if (sessionContext) {
|
|
48
|
+
request.sessionContext = sessionContext;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const requestJson = JSON.stringify(request) + "\n";
|
|
52
|
+
|
|
53
|
+
let conn: Deno.UnixConn;
|
|
54
|
+
try {
|
|
55
|
+
conn = await Deno.connect({ transport: "unix", path: SOCKET_PATH });
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error(
|
|
58
|
+
`Failed to connect to gateway socket at ${SOCKET_PATH}:`,
|
|
59
|
+
err instanceof Error ? err.message : err
|
|
60
|
+
);
|
|
61
|
+
Deno.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const encoder = new TextEncoder();
|
|
65
|
+
const decoder = new TextDecoder();
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
await conn.write(encoder.encode(requestJson));
|
|
69
|
+
|
|
70
|
+
let responseText = "";
|
|
71
|
+
const buf = new Uint8Array(65536);
|
|
72
|
+
while (!responseText.includes("\n")) {
|
|
73
|
+
const n = await conn.read(buf);
|
|
74
|
+
if (n === null) break;
|
|
75
|
+
responseText += decoder.decode(buf.subarray(0, n));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
conn.close();
|
|
79
|
+
|
|
80
|
+
const parsed = JSON.parse(responseText.trim());
|
|
81
|
+
if (parsed.success) {
|
|
82
|
+
if (parsed.output) {
|
|
83
|
+
await Deno.stdout.write(encoder.encode(parsed.output));
|
|
84
|
+
}
|
|
85
|
+
Deno.exit(parsed.exitCode ?? 0);
|
|
86
|
+
} else {
|
|
87
|
+
if (parsed.error) {
|
|
88
|
+
await Deno.stderr.write(encoder.encode(parsed.error + "\n"));
|
|
89
|
+
}
|
|
90
|
+
Deno.exit(parsed.exitCode ?? 1);
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error("Failed to communicate with gateway:", err instanceof Error ? err.message : err);
|
|
94
|
+
Deno.exit(1);
|
|
95
|
+
}
|