@agentbean/daemon 0.1.28 → 0.1.31

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.
@@ -11,6 +11,10 @@ function buildPrompt(input, systemPrompt) {
11
11
  parts.push(input.prompt);
12
12
  return parts.join('\n\n---\n\n');
13
13
  }
14
+ function normalizeClaudeArgs(args) {
15
+ const filtered = (args ?? []).filter((arg) => arg !== '--bare');
16
+ return ['-p', ...filtered];
17
+ }
14
18
  export class ClaudeCodeAdapter {
15
19
  opts;
16
20
  kind = 'claude-code';
@@ -21,7 +25,7 @@ export class ClaudeCodeAdapter {
21
25
  return new Promise((resolve, reject) => {
22
26
  const prompt = buildPrompt(input, this.opts.systemPrompt ?? input.systemPrompt);
23
27
  const cwd = input.workspace ?? this.opts.cwd ?? process.cwd();
24
- const baseArgs = ['-p', '--bare', ...(this.opts.args ?? [])];
28
+ const baseArgs = normalizeClaudeArgs(this.opts.args);
25
29
  if (input.workspace)
26
30
  baseArgs.push('--add-dir', input.workspace);
27
31
  baseArgs.push('--add-dir', join(homedir(), '.codex', 'generated_images'));
@@ -1,4 +1,6 @@
1
1
  import { spawn } from 'node-pty';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
2
4
  function renderPayload(input, systemPrompt) {
3
5
  const parts = [];
4
6
  if (systemPrompt)
@@ -52,6 +54,19 @@ function adapterTimeoutMs() {
52
54
  const fromEnv = Number.parseInt(process.env.AGENTBEAN_CODEX_TIMEOUT_MS ?? '', 10);
53
55
  return Number.isFinite(fromEnv) && fromEnv > 0 ? fromEnv : 900_000;
54
56
  }
57
+ function buildRuntimeEnv(extra) {
58
+ const pathEntries = [
59
+ process.env.PATH,
60
+ '/opt/homebrew/bin',
61
+ '/usr/local/bin',
62
+ join(homedir(), '.local/bin'),
63
+ join(homedir(), '.bun/bin'),
64
+ join(homedir(), '.npm-global/bin'),
65
+ join(homedir(), '.asdf/shims'),
66
+ join(homedir(), '.local/share/mise/shims'),
67
+ ].filter(Boolean).join(':');
68
+ return { ...process.env, PATH: pathEntries, ...(extra ?? {}) };
69
+ }
55
70
  export class CodexAdapter {
56
71
  opts;
57
72
  kind = 'codex';
@@ -74,7 +89,7 @@ export class CodexAdapter {
74
89
  cols: 80,
75
90
  rows: 30,
76
91
  cwd,
77
- env: { ...process.env, ...(input.env ?? {}) },
92
+ env: buildRuntimeEnv(input.env),
78
93
  });
79
94
  const chunks = [];
80
95
  let finished = false;
@@ -128,7 +143,7 @@ export class CodexAdapter {
128
143
  const pty = spawn('bash', ['-c', 'codex --version'], {
129
144
  name: 'xterm-color', cols: 80, rows: 30,
130
145
  cwd: this.opts.cwd ?? process.cwd(),
131
- env: process.env,
146
+ env: buildRuntimeEnv(),
132
147
  });
133
148
  pty.onExit(({ exitCode }) => resolve({ ok: exitCode === 0, detail: exitCode === 0 ? undefined : `exit ${exitCode}` }));
134
149
  }
@@ -1,7 +1,7 @@
1
1
  import { io } from 'socket.io-client';
2
2
  import { execFile } from 'node:child_process';
3
3
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
4
- import { join } from 'node:path';
4
+ import { basename, isAbsolute, join } from 'node:path';
5
5
  import { homedir } from 'node:os';
6
6
  import { promisify } from 'node:util';
7
7
  import { logger } from './log.js';
@@ -29,6 +29,58 @@ function agentSlug(name) {
29
29
  function scannedAgentId(deviceId, name) {
30
30
  return `scan-${deviceId}-${agentSlug(name)}`;
31
31
  }
32
+ function normalizeAdapterKind(kind) {
33
+ const normalized = (kind ?? '').trim().toLowerCase().replace(/[_\s]+/g, '-');
34
+ if (normalized === 'claude' || normalized === 'claude-code')
35
+ return 'claude-code';
36
+ if (normalized === 'codex' || normalized === 'codex-cli')
37
+ return 'codex';
38
+ if (normalized === 'kimi' || normalized === 'kimi-cli')
39
+ return 'kimi-cli';
40
+ return normalized;
41
+ }
42
+ function runtimeScoreForCustomAgent(runtime, custom) {
43
+ if (!runtime.installed || !runtime.command?.trim())
44
+ return 0;
45
+ const runtimeCommand = runtime.command.trim();
46
+ const customCommand = custom.command?.trim() ?? '';
47
+ if (runtimeCommand && customCommand && runtimeCommand === customCommand)
48
+ return 100;
49
+ const runtimeBase = basename(runtimeCommand).toLowerCase();
50
+ const customBase = customCommand ? basename(customCommand).toLowerCase() : '';
51
+ if (runtimeBase && customBase && runtimeBase === customBase)
52
+ return 90;
53
+ const runtimeKind = normalizeAdapterKind(runtime.adapterKind);
54
+ const customKind = normalizeAdapterKind(custom.adapterKind);
55
+ if (runtimeKind === 'kimi-cli' && customKind === 'codex' && customCommand.toLowerCase().includes('kimi'))
56
+ return 85;
57
+ if (runtimeKind && customKind && runtimeKind === customKind)
58
+ return 70;
59
+ return 0;
60
+ }
61
+ export function resolveCustomAgentRuntime(custom, runtimes) {
62
+ const configured = custom.command?.trim() ?? '';
63
+ const configuredAbsoluteExists = configured && isAbsolute(configured) && existsSync(configured);
64
+ const bestRuntime = [...runtimes]
65
+ .map((runtime) => ({ runtime, score: runtimeScoreForCustomAgent(runtime, custom) }))
66
+ .filter((candidate) => candidate.score > 0)
67
+ .sort((a, b) => b.score - a.score)[0]?.runtime;
68
+ if (configuredAbsoluteExists) {
69
+ return { command: configured, runtime: bestRuntime };
70
+ }
71
+ if (bestRuntime?.command?.trim()) {
72
+ return { command: bestRuntime.command.trim(), runtime: bestRuntime };
73
+ }
74
+ if (configured && isAbsolute(configured) && !configuredAbsoluteExists) {
75
+ const fallback = basename(configured).trim();
76
+ if (fallback)
77
+ return { command: fallback };
78
+ }
79
+ if (!configured && normalizeAdapterKind(custom.adapterKind) === 'codex') {
80
+ return { command: 'codex' };
81
+ }
82
+ return { command: configured };
83
+ }
32
84
  export function nativeDirectoryPickerCommands(platform = process.platform) {
33
85
  if (platform === 'darwin') {
34
86
  return [{ command: 'osascript', args: ['-e', 'POSIX path of (choose folder with prompt "选择项目目录")'] }];
@@ -184,10 +236,12 @@ export function createDeviceDaemon(cfg, agents) {
184
236
  const httpBase = cfg.server.url.replace(/\/agent$/, '');
185
237
  let firstConnect = true;
186
238
  const systemInfo = collectSystemInfo();
239
+ let latestRuntimes = [];
187
240
  const publicAgents = Array.from(agents.values())
188
241
  .filter((a) => a.visibility === 'public')
189
242
  .map((a) => a.publicMeta);
190
243
  function emitRegister(sock, payload) {
244
+ latestRuntimes = payload.runtimes.filter((runtime) => runtime.installed);
191
245
  if (payload.runtimes.length > 0) {
192
246
  sock.emit('device:register-runtimes', { runtimes: payload.runtimes }, (ack) => {
193
247
  if (!ack?.ok)
@@ -323,8 +377,9 @@ export function createDeviceDaemon(cfg, agents) {
323
377
  });
324
378
  socket.on('dispatch', (req) => {
325
379
  let agent = agents.get(req.agentId);
326
- if (!agent && req.customAgent) {
380
+ if (req.customAgent) {
327
381
  const custom = req.customAgent;
382
+ const resolvedRuntime = resolveCustomAgentRuntime(custom, latestRuntimes);
328
383
  const entry = {
329
384
  id: custom.id,
330
385
  name: custom.name,
@@ -332,7 +387,7 @@ export function createDeviceDaemon(cfg, agents) {
332
387
  category: 'executor-hosted',
333
388
  adapter: {
334
389
  kind: custom.adapterKind,
335
- command: custom.command,
390
+ command: resolvedRuntime.command,
336
391
  args: custom.args ?? [],
337
392
  cwd: custom.cwd ?? undefined,
338
393
  workspace: custom.cwd ?? undefined,
@@ -343,7 +398,14 @@ export function createDeviceDaemon(cfg, agents) {
343
398
  try {
344
399
  agent = new AgentInstance(entry, pickAdapter(entry.adapter));
345
400
  agents.set(req.agentId, agent);
346
- logger.info({ agentId: req.agentId, kind: entry.adapter.kind, cwd: entry.adapter.cwd }, 'custom agent instance created for dispatch');
401
+ logger.info({
402
+ agentId: req.agentId,
403
+ kind: entry.adapter.kind,
404
+ command: entry.adapter.command,
405
+ configuredCommand: custom.command,
406
+ runtimeCommand: resolvedRuntime.runtime?.command,
407
+ cwd: entry.adapter.cwd,
408
+ }, 'custom agent instance created for dispatch');
347
409
  }
348
410
  catch (err) {
349
411
  logger.warn({ agentId: req.agentId, err: errorMessage(err) }, 'failed to create custom dispatch agent');
package/dist/scanner.js CHANGED
@@ -285,14 +285,14 @@ async function checkOpenClawGateway() {
285
285
  return null;
286
286
  const status = await run(path, ["gateway", "status"]);
287
287
  const running = status.includes("running") || status.includes("✓");
288
- if (running) {
289
- const agentId = parseOpenClawAgentId(await run(path, ["agents", "list", "--json"])) ?? "main";
288
+ const agentId = parseOpenClawAgentId(await run(path, ["agents", "list", "--json"]));
289
+ if (running || agentId) {
290
290
  return {
291
291
  category: "agentos-hosted",
292
292
  name: "OpenClaw-Agent",
293
293
  adapterKind: "openclaw",
294
294
  command: path,
295
- args: ["agent", "--agent", agentId],
295
+ args: ["agent", "--agent", agentId ?? "main"],
296
296
  source: "gateway",
297
297
  };
298
298
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agentbean/daemon",
3
3
  "private": false,
4
- "version": "0.1.28",
4
+ "version": "0.1.31",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {