@agentbean/daemon 0.1.26 → 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/device-daemon.js +68 -0
- package/package.json +1 -1
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
|
});
|