@agentbean/daemon 0.1.25 → 0.1.27
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/openclaw.js +28 -7
- package/dist/device-daemon.js +68 -0
- package/dist/scanner.js +32 -2
- package/package.json +1 -1
|
@@ -8,16 +8,37 @@ function runtimeArgs(args = []) {
|
|
|
8
8
|
function hasMessageFlag(args) {
|
|
9
9
|
return args.includes('--message') || args.includes('-m');
|
|
10
10
|
}
|
|
11
|
+
function hasTargetSelector(args) {
|
|
12
|
+
return args.includes('--agent')
|
|
13
|
+
|| args.includes('--session-id')
|
|
14
|
+
|| args.includes('--session-key')
|
|
15
|
+
|| args.includes('--to')
|
|
16
|
+
|| args.includes('-t');
|
|
17
|
+
}
|
|
18
|
+
function ensureTargetSelector(args) {
|
|
19
|
+
if (hasTargetSelector(args))
|
|
20
|
+
return args;
|
|
21
|
+
const messageIdx = args.findIndex((arg) => arg === '--message' || arg === '-m');
|
|
22
|
+
if (messageIdx >= 0) {
|
|
23
|
+
return [
|
|
24
|
+
...args.slice(0, messageIdx),
|
|
25
|
+
'--agent',
|
|
26
|
+
'main',
|
|
27
|
+
...args.slice(messageIdx),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return [...args, '--agent', 'main'];
|
|
31
|
+
}
|
|
11
32
|
function buildArgs(baseArgs, prompt) {
|
|
12
|
-
// Current OpenClaw one-shot agent turns
|
|
33
|
+
// Current OpenClaw one-shot agent turns require an explicit session selector.
|
|
13
34
|
// Preserve explicit custom args when the message flag is already configured.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (
|
|
18
|
-
return [...
|
|
35
|
+
const agentArgs = baseArgs.includes('agent')
|
|
36
|
+
? ensureTargetSelector(baseArgs)
|
|
37
|
+
: [...baseArgs, 'agent', '--agent', 'main'];
|
|
38
|
+
if (hasMessageFlag(agentArgs)) {
|
|
39
|
+
return [...agentArgs, prompt];
|
|
19
40
|
}
|
|
20
|
-
return [...
|
|
41
|
+
return [...agentArgs, '--message', prompt];
|
|
21
42
|
}
|
|
22
43
|
function buildPrompt(input, systemPrompt) {
|
|
23
44
|
const parts = [];
|
package/dist/device-daemon.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { io } from 'socket.io-client';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
2
3
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
5
|
import { homedir } from 'node:os';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
5
7
|
import { logger } from './log.js';
|
|
6
8
|
import { AgentInstance } from './agent-instance.js';
|
|
7
9
|
import { pickAdapter } from './adapters/factory.js';
|
|
8
10
|
import { scanRuntimes, scanAgentOSAgents, scanLocalAgents, collectSystemInfo } from './scanner.js';
|
|
9
11
|
import { syncWorkspaceArtifacts } from './workspace-sync.js';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
10
13
|
function errorMessage(err) {
|
|
11
14
|
if (err instanceof Error && err.message)
|
|
12
15
|
return err.message;
|
|
@@ -26,6 +29,55 @@ function agentSlug(name) {
|
|
|
26
29
|
function scannedAgentId(deviceId, name) {
|
|
27
30
|
return `scan-${deviceId}-${agentSlug(name)}`;
|
|
28
31
|
}
|
|
32
|
+
export function nativeDirectoryPickerCommands(platform = process.platform) {
|
|
33
|
+
if (platform === 'darwin') {
|
|
34
|
+
return [{ command: 'osascript', args: ['-e', 'POSIX path of (choose folder with prompt "选择项目目录")'] }];
|
|
35
|
+
}
|
|
36
|
+
if (platform === 'win32') {
|
|
37
|
+
return [{
|
|
38
|
+
command: 'powershell.exe',
|
|
39
|
+
args: [
|
|
40
|
+
'-NoProfile',
|
|
41
|
+
'-STA',
|
|
42
|
+
'-Command',
|
|
43
|
+
'Add-Type -AssemblyName System.Windows.Forms; $dialog = New-Object System.Windows.Forms.FolderBrowserDialog; if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { $dialog.SelectedPath }',
|
|
44
|
+
],
|
|
45
|
+
}];
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
{ command: 'zenity', args: ['--file-selection', '--directory', '--title=选择项目目录'] },
|
|
49
|
+
{ command: 'kdialog', args: ['--getexistingdirectory', '.', '选择项目目录'] },
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
function isMissingCommandError(err) {
|
|
53
|
+
return err?.code === 'ENOENT';
|
|
54
|
+
}
|
|
55
|
+
function isDirectoryPickerCancel(err) {
|
|
56
|
+
const message = `${err?.message ?? ''}\n${err?.stderr ?? ''}`;
|
|
57
|
+
return err?.code === 1 || /cancel|canceled|cancelled|User canceled|No file selected/i.test(message);
|
|
58
|
+
}
|
|
59
|
+
export async function selectNativeDirectory(commands = nativeDirectoryPickerCommands()) {
|
|
60
|
+
let lastError = null;
|
|
61
|
+
for (const cmd of commands) {
|
|
62
|
+
try {
|
|
63
|
+
const { stdout } = await execFileAsync(cmd.command, cmd.args, { timeout: 120_000 });
|
|
64
|
+
const selected = stdout.trim();
|
|
65
|
+
if (selected)
|
|
66
|
+
return selected;
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (isMissingCommandError(err)) {
|
|
71
|
+
lastError = err;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (isDirectoryPickerCancel(err))
|
|
75
|
+
return null;
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
throw new Error(lastError ? `directory picker command not available: ${errorMessage(lastError)}` : 'directory picker command not available');
|
|
80
|
+
}
|
|
29
81
|
const CACHE_DIR = join(homedir(), '.agentbean');
|
|
30
82
|
const CACHE_FILE = join(CACHE_DIR, 'scanned-agents.json');
|
|
31
83
|
function isRuntimeEntry(entry) {
|
|
@@ -88,6 +140,7 @@ export function createDeviceSocketOptions(input) {
|
|
|
88
140
|
protocolVersion: 1,
|
|
89
141
|
capabilities: {
|
|
90
142
|
customAgentDispatch: true,
|
|
143
|
+
directoryPicker: true,
|
|
91
144
|
},
|
|
92
145
|
},
|
|
93
146
|
reconnection: true,
|
|
@@ -347,6 +400,21 @@ export function createDeviceDaemon(cfg, agents) {
|
|
|
347
400
|
}
|
|
348
401
|
logger.info({ agentId: payload.agentId, requestId: payload.requestId, cancelled, reason: payload.reason }, 'dispatch cancel requested');
|
|
349
402
|
});
|
|
403
|
+
socket.on('device:select-directory', async (_payload, ack) => {
|
|
404
|
+
try {
|
|
405
|
+
const selected = await selectNativeDirectory();
|
|
406
|
+
if (!selected) {
|
|
407
|
+
ack?.({ ok: false, error: 'CANCELLED' });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
ack?.({ ok: true, path: selected });
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
const message = errorMessage(err);
|
|
414
|
+
logger.warn({ err: message }, 'failed to select directory on device');
|
|
415
|
+
ack?.({ ok: false, error: message });
|
|
416
|
+
}
|
|
417
|
+
});
|
|
350
418
|
socket.on('agents:discover', async () => {
|
|
351
419
|
await scanAndRegister(socket, false);
|
|
352
420
|
});
|
package/dist/scanner.js
CHANGED
|
@@ -96,6 +96,35 @@ function run(bin, args) {
|
|
|
96
96
|
child.on("error", () => resolve(""));
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
|
+
export function parseOpenClawAgentId(output) {
|
|
100
|
+
if (!output.trim())
|
|
101
|
+
return null;
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(output);
|
|
104
|
+
const list = Array.isArray(parsed)
|
|
105
|
+
? parsed
|
|
106
|
+
: Array.isArray(parsed?.agents)
|
|
107
|
+
? parsed.agents
|
|
108
|
+
: Array.isArray(parsed?.items)
|
|
109
|
+
? parsed.items
|
|
110
|
+
: [];
|
|
111
|
+
for (const item of list) {
|
|
112
|
+
const id = typeof item === 'string'
|
|
113
|
+
? item
|
|
114
|
+
: typeof item?.id === 'string'
|
|
115
|
+
? item.id
|
|
116
|
+
: typeof item?.agentId === 'string'
|
|
117
|
+
? item.agentId
|
|
118
|
+
: null;
|
|
119
|
+
if (id?.trim())
|
|
120
|
+
return id.trim();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
99
128
|
// --- Machine ID (stable per-device identifier) ---
|
|
100
129
|
const MACHINE_ID_FILE = join(os.homedir(), ".agentbean", "device-id");
|
|
101
130
|
function getFirstMacAddress() {
|
|
@@ -254,15 +283,16 @@ async function checkOpenClawGateway() {
|
|
|
254
283
|
const path = await which("openclaw");
|
|
255
284
|
if (!path)
|
|
256
285
|
return null;
|
|
257
|
-
const status = await run(
|
|
286
|
+
const status = await run(path, ["gateway", "status"]);
|
|
258
287
|
const running = status.includes("running") || status.includes("✓");
|
|
259
288
|
if (running) {
|
|
289
|
+
const agentId = parseOpenClawAgentId(await run(path, ["agents", "list", "--json"])) ?? "main";
|
|
260
290
|
return {
|
|
261
291
|
category: "agentos-hosted",
|
|
262
292
|
name: "OpenClaw-Agent",
|
|
263
293
|
adapterKind: "openclaw",
|
|
264
294
|
command: path,
|
|
265
|
-
args: [],
|
|
295
|
+
args: ["agent", "--agent", agentId],
|
|
266
296
|
source: "gateway",
|
|
267
297
|
};
|
|
268
298
|
}
|