@agentbean/daemon 0.1.33 → 0.1.34
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/adapters/hermes.js +13 -2
- package/dist/agent-instance.js +1 -1
- package/dist/device-daemon.js +2 -0
- package/dist/index.js +4 -3
- package/dist/sandbox.js +7 -2
- package/dist/workspace-manager.js +29 -4
- package/package.json +1 -1
package/dist/adapters/hermes.js
CHANGED
|
@@ -27,11 +27,22 @@ function buildPrompt(input, systemPrompt) {
|
|
|
27
27
|
}
|
|
28
28
|
const ANSI_RE = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
29
29
|
const BOX_ONLY_RE = /^[\s─━═╭╮╰╯│┃┌┐└┘├┤┬┴┼]+$/;
|
|
30
|
+
function stripEchoedQueryPreamble(lines) {
|
|
31
|
+
const initIdx = lines.findIndex((line) => {
|
|
32
|
+
const trimmed = line.trim();
|
|
33
|
+
return trimmed === 'Initializing agent...' || trimmed === 'Initializing agent…';
|
|
34
|
+
});
|
|
35
|
+
if (initIdx < 0)
|
|
36
|
+
return lines;
|
|
37
|
+
if (!lines.slice(0, initIdx).some((line) => line.trim().startsWith('Query:')))
|
|
38
|
+
return lines;
|
|
39
|
+
return lines.slice(initIdx + 1);
|
|
40
|
+
}
|
|
30
41
|
export function extractHermesReply(output) {
|
|
31
|
-
const lines = output
|
|
42
|
+
const lines = stripEchoedQueryPreamble(output
|
|
32
43
|
.replace(ANSI_RE, '')
|
|
33
44
|
.replace(/\r\n?/g, '\n')
|
|
34
|
-
.split('\n');
|
|
45
|
+
.split('\n'));
|
|
35
46
|
let boxStart = -1;
|
|
36
47
|
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
37
48
|
if (lines[i]?.trim().startsWith('╭')) {
|
package/dist/agent-instance.js
CHANGED
|
@@ -106,7 +106,7 @@ export class AgentInstance {
|
|
|
106
106
|
systemPrompt: this.config.adapter.systemPrompt,
|
|
107
107
|
workspace: projectWorkspace,
|
|
108
108
|
sandboxProfilePath: req.sandboxed && isSandboxAvailable()
|
|
109
|
-
? generateSandboxProfile(this.id, this.config.adapter.command)
|
|
109
|
+
? generateSandboxProfile(this.id, this.config.adapter.command, [run.runDir])
|
|
110
110
|
: undefined,
|
|
111
111
|
env: { ...(this.config.adapter.env ?? {}), ...workspaceEnv(run) },
|
|
112
112
|
}, ctl.signal);
|
package/dist/device-daemon.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -153,7 +153,8 @@ Options:
|
|
|
153
153
|
console.error('Error: --server-url is required with --invite.');
|
|
154
154
|
process.exit(1);
|
|
155
155
|
}
|
|
156
|
-
const
|
|
156
|
+
const inviteDeviceId = values['device-id'] ?? await getDeviceId();
|
|
157
|
+
const auth = await runInviteMode(serverUrl, values.invite, inviteDeviceId);
|
|
157
158
|
serverUrl = auth.serverUrl;
|
|
158
159
|
token = auth.token;
|
|
159
160
|
networkId = auth.networkId ?? networkId;
|
|
@@ -238,7 +239,7 @@ export function socketErrorMessage(err) {
|
|
|
238
239
|
.map((value) => value.trim());
|
|
239
240
|
return [...new Set(details)].join(': ') || 'unknown socket error';
|
|
240
241
|
}
|
|
241
|
-
async function runInviteMode(serverUrl, inviteCode) {
|
|
242
|
+
async function runInviteMode(serverUrl, inviteCode, deviceId) {
|
|
242
243
|
const { io } = await import('socket.io-client');
|
|
243
244
|
const { execFile } = await import('node:child_process');
|
|
244
245
|
const baseUrl = normalizeBaseUrl(serverUrl);
|
|
@@ -265,7 +266,7 @@ async function runInviteMode(serverUrl, inviteCode) {
|
|
|
265
266
|
clearTimeout(connectTimer);
|
|
266
267
|
logger.info('invite mode: connected, validating invite code');
|
|
267
268
|
console.log('Connected. Validating invite code...');
|
|
268
|
-
socket.emit('auth:invite:validate', { code: inviteCode }, (res) => {
|
|
269
|
+
socket.emit('auth:invite:validate', { code: inviteCode, deviceId }, (res) => {
|
|
269
270
|
if (!res?.ok) {
|
|
270
271
|
fail(new Error(res?.error ?? 'invalid invite code'));
|
|
271
272
|
return;
|
package/dist/sandbox.js
CHANGED
|
@@ -21,16 +21,21 @@ export function isSandboxAvailable() {
|
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
export function generateSandboxProfile(agentId, runtimePath) {
|
|
24
|
+
export function generateSandboxProfile(agentId, runtimePath, writableDirs = []) {
|
|
25
25
|
const workspaceDir = getWorkspaceDir(agentId);
|
|
26
26
|
const runtimeDir = runtimePath.includes('/') ? dirname(runtimePath) : '/usr/bin';
|
|
27
27
|
const profilePath = `/tmp/agentbean-sandbox-${agentId}.sb`;
|
|
28
|
+
const extraWritableRules = writableDirs
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.map((dir) => `(allow file-read* file-write*
|
|
31
|
+
(subpath "${escapeSchemeString(dir)}"))`)
|
|
32
|
+
.join('\n');
|
|
28
33
|
const profile = `(version 1)
|
|
29
34
|
(allow file-read* file-write*
|
|
30
35
|
(subpath "${escapeSchemeString(workspaceDir)}"))
|
|
31
36
|
(allow file-read* file-write*
|
|
32
37
|
(subpath "/tmp"))
|
|
33
|
-
(allow file-read*
|
|
38
|
+
${extraWritableRules ? `${extraWritableRules}\n` : ''}(allow file-read*
|
|
34
39
|
(subpath "${escapeSchemeString(runtimeDir)}"))
|
|
35
40
|
(allow file-read*
|
|
36
41
|
(subpath "/bin")
|
|
@@ -34,6 +34,14 @@ function uniqueDestination(dir, filename) {
|
|
|
34
34
|
}
|
|
35
35
|
return candidate;
|
|
36
36
|
}
|
|
37
|
+
function fileNamePreference(path) {
|
|
38
|
+
const name = basename(path).toLowerCase();
|
|
39
|
+
if (/^ig_[a-f0-9]{32,}\.(png|jpe?g|gif|webp)$/i.test(name))
|
|
40
|
+
return 0;
|
|
41
|
+
if (/^(image|output|generated)[._-]?\d*\.(png|jpe?g|gif|webp)$/i.test(name))
|
|
42
|
+
return 1;
|
|
43
|
+
return 2;
|
|
44
|
+
}
|
|
37
45
|
function escapeRegExp(value) {
|
|
38
46
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
39
47
|
}
|
|
@@ -94,12 +102,14 @@ export function workspaceEnv(run) {
|
|
|
94
102
|
}
|
|
95
103
|
export function archiveOutputFiles(run, files) {
|
|
96
104
|
const archived = [];
|
|
97
|
-
const
|
|
105
|
+
const candidates = new Map();
|
|
106
|
+
const hashOrder = [];
|
|
107
|
+
const seenPaths = new Set();
|
|
98
108
|
for (const file of files) {
|
|
99
109
|
const abs = isAbsolute(file) ? file : resolve(file);
|
|
100
|
-
if (
|
|
110
|
+
if (seenPaths.has(abs))
|
|
101
111
|
continue;
|
|
102
|
-
|
|
112
|
+
seenPaths.add(abs);
|
|
103
113
|
let st;
|
|
104
114
|
try {
|
|
105
115
|
st = statSync(abs);
|
|
@@ -109,6 +119,21 @@ export function archiveOutputFiles(run, files) {
|
|
|
109
119
|
catch {
|
|
110
120
|
continue;
|
|
111
121
|
}
|
|
122
|
+
const hash = fileHash(abs);
|
|
123
|
+
const current = candidates.get(hash);
|
|
124
|
+
if (!current) {
|
|
125
|
+
candidates.set(hash, { abs, hash });
|
|
126
|
+
hashOrder.push(hash);
|
|
127
|
+
}
|
|
128
|
+
else if (fileNamePreference(abs) > fileNamePreference(current.abs)) {
|
|
129
|
+
candidates.set(hash, { abs, hash });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const hash of hashOrder) {
|
|
133
|
+
const candidate = candidates.get(hash);
|
|
134
|
+
if (!candidate)
|
|
135
|
+
continue;
|
|
136
|
+
const abs = candidate.abs;
|
|
112
137
|
const alreadyInRun = relative(run.runDir, abs);
|
|
113
138
|
const archivedPath = alreadyInRun && !alreadyInRun.startsWith('..') && !isAbsolute(alreadyInRun)
|
|
114
139
|
? abs
|
|
@@ -121,7 +146,7 @@ export function archiveOutputFiles(run, files) {
|
|
|
121
146
|
archivedPath,
|
|
122
147
|
relativePath: relative(run.agentDir, archivedPath),
|
|
123
148
|
pathKind: 'output',
|
|
124
|
-
sha256:
|
|
149
|
+
sha256: candidate.hash,
|
|
125
150
|
sizeBytes,
|
|
126
151
|
});
|
|
127
152
|
}
|