@openagents-org/agent-connector 0.1.9 → 0.1.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/daemon.js +78 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-connector",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Agent management CLI and library for OpenAgents — install, configure, and run AI coding agents",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/daemon.js CHANGED
@@ -372,6 +372,11 @@ class Daemon {
372
372
  // Send initial heartbeat
373
373
  try { await wsClient.heartbeat(network.id, name, network.token); } catch {}
374
374
 
375
+ // Install workspace skill into OpenClaw's skills directory
376
+ try { this._installWorkspaceSkill(agentCfg, network); } catch (e) {
377
+ this._log(`${name} skill install failed: ${e.message}`);
378
+ }
379
+
375
380
  info.state = 'running';
376
381
  info.startedAt = new Date().toISOString();
377
382
  this._writeStatus();
@@ -504,36 +509,74 @@ class Daemon {
504
509
  return { binary: process.env.COMSPEC || 'cmd.exe', prefix: ['/C', binary] };
505
510
  }
506
511
 
507
- _buildWorkspaceContext(agentCfg, network) {
512
+ /**
513
+ * Install a SKILL.md into OpenClaw's workspace skills directory.
514
+ * OpenClaw auto-discovers skills from <workspace>/skills/ and injects
515
+ * them into the system prompt — same mechanism as the Python adapter.
516
+ */
517
+ _installWorkspaceSkill(agentCfg, network) {
508
518
  const baseUrl = 'https://workspace-endpoint.openagents.org';
509
519
  const h = `Authorization: Bearer ${network.token}`;
510
520
  const wsId = network.id;
511
521
  const name = agentCfg.name;
522
+ const agentId = agentCfg.openclaw_agent_id || 'main';
523
+
524
+ const home = IS_WINDOWS ? process.env.USERPROFILE : process.env.HOME;
525
+ const openclawDir = path.join(home, '.openclaw');
526
+ const wsDir = agentId && agentId !== 'main'
527
+ ? path.join(openclawDir, `workspace-${agentId}`)
528
+ : path.join(openclawDir, 'workspace');
512
529
 
513
- return [
514
- '=== WORKSPACE CONTEXT ===',
515
- `You are agent "${name}" in workspace "${network.slug}".`,
516
- 'You have access to shared workspace tools via HTTP API. Use your exec tool to run curl commands.',
530
+ if (!fs.existsSync(wsDir)) {
531
+ this._log(`OpenClaw workspace not found at ${wsDir}, skipping skill install`);
532
+ return;
533
+ }
534
+
535
+ const skillName = `openagents-workspace-${name}`;
536
+ const skillDir = path.join(wsDir, 'skills', skillName);
537
+ fs.mkdirSync(skillDir, { recursive: true });
538
+
539
+ const content = [
540
+ '---',
541
+ 'name: openagents-workspace',
542
+ 'description: "Share files, browse websites, and collaborate with other agents in an OpenAgents workspace. Use when: (1) sharing results or reports, (2) browsing a website, (3) reading shared files, (4) checking who else is in the workspace."',
543
+ 'metadata:',
544
+ ' {"openclaw": {"always": true, "emoji": "\\U0001F310"}}',
545
+ '---',
546
+ '',
547
+ `You are agent "${name}" in workspace "${network.slug || network.name || wsId}".`,
548
+ '',
549
+ '## Workspace Tools (MANDATORY)',
517
550
  '',
518
- '## Shared Browser',
519
- 'The workspace has a shared browser visible to all users and agents.',
520
- `Open tab: curl -s -X POST ${baseUrl}/v1/browser/tabs -H "${h}" -H "Content-Type: application/json" -d '{"url":"URL","network":"${wsId}","source":"openagents:${name}"}'`,
521
- `Read page: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/snapshot`,
522
- `Screenshot: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/screenshot`,
523
- `Navigate: curl -s -X POST ${baseUrl}/v1/browser/tabs/TAB_ID/navigate -H "${h}" -H "Content-Type: application/json" -d '{"url":"URL"}'`,
524
- `Click: curl -s -X POST ${baseUrl}/v1/browser/tabs/TAB_ID/click -H "${h}" -H "Content-Type: application/json" -d '{"selector":"CSS_SELECTOR"}'`,
525
- `Type: curl -s -X POST ${baseUrl}/v1/browser/tabs/TAB_ID/type -H "${h}" -H "Content-Type: application/json" -d '{"selector":"CSS_SELECTOR","text":"TEXT"}'`,
526
- `Close: curl -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID`,
527
- `List tabs: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs?network=${wsId}`,
528
- '(Replace TAB_ID with the id from the open response)',
551
+ 'Use your `exec` tool to run the `curl` commands below.',
552
+ 'Do NOT use native browsing tools for workspace browser tasks use `exec` + `curl`.',
553
+ 'The workspace browser is a *shared* browser visible to all users and agents.',
529
554
  '',
530
- '## Workspace Files',
531
- `List: curl -s -H "${h}" ${baseUrl}/v1/files?network=${wsId}`,
532
- `Read: curl -s -H "${h}" ${baseUrl}/v1/files/FILE_PATH?network=${wsId}`,
533
- `Write: curl -s -X PUT ${baseUrl}/v1/files/FILE_PATH -H "${h}" -H "Content-Type: application/json" -d '{"content":"...","network":"${wsId}"}'`,
534
- '=== END WORKSPACE CONTEXT ===',
555
+ '### Shared Browser',
556
+ '',
557
+ '**To browse a website**, exec these steps:',
558
+ `Step 1 — open tab: curl -s -X POST ${baseUrl}/v1/browser/tabs -H "${h}" -H "Content-Type: application/json" -d '{"url":"https://example.com","network":"${wsId}","source":"openagents:${name}"}'`,
559
+ `Step 2 read content: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/snapshot`,
560
+ `Step 3 — close tab: curl -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID`,
561
+ '(Replace TAB_ID with the id from step 1 response)',
562
+ '',
563
+ `List tabs: \`curl -s -H "${h}" ${baseUrl}/v1/browser/tabs?network=${wsId}\``,
564
+ `Navigate: \`curl -s -X POST -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/browser/tabs/{tab_id}/navigate -d '{"url":"URL"}'\``,
565
+ `Click: \`curl -s -X POST -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/browser/tabs/{tab_id}/click -d '{"selector":"CSS"}'\``,
566
+ `Type: \`curl -s -X POST -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/browser/tabs/{tab_id}/type -d '{"selector":"CSS","text":"TEXT"}'\``,
567
+ `Close: \`curl -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/{tab_id}\``,
568
+ '',
569
+ '### Workspace Files',
570
+ '',
571
+ `List: \`curl -s -H "${h}" ${baseUrl}/v1/files?network=${wsId}\``,
572
+ `Read: \`curl -s -H "${h}" ${baseUrl}/v1/files/FILE_PATH?network=${wsId}\``,
573
+ `Write: \`curl -s -X PUT -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/files/FILE_PATH -d '{"content":"...","network":"${wsId}"}'\``,
535
574
  '',
536
575
  ].join('\n');
576
+
577
+ const skillPath = path.join(skillDir, 'SKILL.md');
578
+ fs.writeFileSync(skillPath, content, 'utf-8');
579
+ this._log(`Installed workspace skill at ${skillPath}`);
537
580
  }
538
581
 
539
582
  _runCliAgent(binary, message, channel, agentCfg, network, env) {
@@ -541,34 +584,10 @@ class Daemon {
541
584
  const sessionKey = `openagents-${network.id.slice(0, 8)}-${channel.slice(-8)}`;
542
585
  const agentId = agentCfg.openclaw_agent_id || 'main';
543
586
 
544
- // Prepend workspace context on first message in a session
545
- const contextKey = `${agentCfg.name}:${sessionKey}`;
546
- let fullMessage = message;
547
- if (!this._sessionContextSent) this._sessionContextSent = new Set();
548
- if (!this._sessionContextSent.has(contextKey)) {
549
- fullMessage = this._buildWorkspaceContext(agentCfg, network) + message;
550
- this._sessionContextSent.add(contextKey);
551
- }
587
+ const args = ['agent', '--local', '--agent', agentId,
588
+ '--session-id', sessionKey, '--message', message, '--json'];
552
589
 
553
- // Write message to temp file to avoid cmd.exe argument length limits
554
- const msgFile = path.join(this.config.configDir, `msg-${Date.now()}.tmp`);
555
- fs.writeFileSync(msgFile, fullMessage, 'utf-8');
556
-
557
- // Use a small node wrapper to read the message file and exec openclaw
558
- // This avoids all cmd.exe quoting/length issues
559
- const wrapperCode = [
560
- `const msg = require("fs").readFileSync(${JSON.stringify(msgFile)}, "utf-8");`,
561
- `const cp = require("child_process");`,
562
- `const args = ${JSON.stringify(['agent', '--local', '--agent', agentId, '--session-id', sessionKey, '--json'])};`,
563
- `args.push("--message", msg);`,
564
- `const r = cp.spawnSync(${JSON.stringify(binary)}, args, { stdio: ["ignore", "pipe", "pipe"], env: process.env, shell: true, timeout: 600000 });`,
565
- `try { require("fs").unlinkSync(${JSON.stringify(msgFile)}); } catch {}`,
566
- `if (r.stdout) process.stdout.write(r.stdout);`,
567
- `if (r.stderr) process.stderr.write(r.stderr);`,
568
- `process.exit(r.status || 0);`,
569
- ].join('\n');
570
-
571
- this._log(`${agentCfg.name} CLI: ${binary} agent --local --agent ${agentId} ... (via wrapper, msg ${fullMessage.length} chars)`);
590
+ this._log(`${agentCfg.name} CLI: ${binary} ${args.slice(0, 5).join(' ')} ...`);
572
591
 
573
592
  const spawnEnv = { ...env };
574
593
  if (IS_WINDOWS) {
@@ -578,14 +597,22 @@ class Daemon {
578
597
  }
579
598
  }
580
599
 
581
- const spawnBinary = process.execPath; // node
582
- const spawnArgs = ['-e', wrapperCode];
600
+ // On Windows, use cmd.exe /C for .cmd shim resolution
601
+ let spawnBinary = binary;
602
+ let spawnArgs = args;
583
603
  const spawnOpts = {
584
604
  stdio: ['ignore', 'pipe', 'pipe'],
585
605
  env: spawnEnv,
586
- timeout: 620000,
606
+ timeout: 600000,
587
607
  };
588
608
 
609
+ if (IS_WINDOWS) {
610
+ spawnBinary = process.env.COMSPEC || 'cmd.exe';
611
+ const quotedArgs = args.map((a) => a.includes(' ') ? `"${a}"` : a);
612
+ spawnArgs = ['/C', binary, ...quotedArgs];
613
+ }
614
+
615
+
589
616
  const proc = spawn(spawnBinary, spawnArgs, spawnOpts);
590
617
  let stdout = '';
591
618
  let stderr = '';