@openagents-org/agent-launcher 0.2.146 → 0.2.148

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-launcher",
3
- "version": "0.2.146",
3
+ "version": "0.2.148",
4
4
  "description": "OpenAgents Launcher — install, configure, and run AI coding agents from your terminal",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -404,30 +404,18 @@ class ClaudeAdapter extends BaseAdapter {
404
404
  throw new Error('claude CLI not found. Install with: curl -fsSL https://claude.ai/install.sh | bash');
405
405
  }
406
406
 
407
- let systemPrompt = '\n' + buildClaudeSystemPrompt({
407
+ // The builder emits the correct tool-reference block for toolMode directly
408
+ // (mcp → workspace_* tools, skills → openagents-workspace skill), so there
409
+ // is no post-hoc string replacement to drift out of sync.
410
+ const systemPrompt = '\n' + buildClaudeSystemPrompt({
408
411
  agentName: this.agentName,
409
412
  workspaceId: this.workspaceId,
410
413
  channelName,
411
414
  mode: this._mode,
412
415
  browserEnabled,
416
+ toolMode: this.toolMode,
413
417
  });
414
418
 
415
- // In skills mode, replace MCP tool references with curl-based instructions
416
- if (this.toolMode === 'skills') {
417
- systemPrompt = systemPrompt
418
- .replace(
419
- 'Use workspace_get_history to read previous messages.\n' +
420
- 'Use workspace_get_agents to see other agents.\n' +
421
- 'Use workspace_put_todos to track your progress. ALWAYS create a to-do list when given multiple tasks or multi-step work.\n' +
422
- 'Use workspace_create_timer to set a reminder that wakes you up later.\n' +
423
- 'Use workspace_create_routine to set up recurring scheduled tasks (e.g. daily reviews).\n',
424
- 'Use the openagents-workspace skill (Bash + curl) for workspace operations:\n' +
425
- 'reading message history, discovering agents, sharing files, browsing,\n' +
426
- 'managing to-do lists, setting timers, and creating routines.\n' +
427
- 'Refer to the skill instructions for the exact curl commands.\n'
428
- );
429
- }
430
-
431
419
  const cmd = [claudeBin, '-p', prompt, '--output-format', 'stream-json', '--verbose'];
432
420
 
433
421
  cmd.push('--append-system-prompt', systemPrompt);
@@ -18,7 +18,7 @@ const { execSync, spawn } = require('child_process');
18
18
  const BaseAdapter = require('./base');
19
19
  const { formatAttachmentsForPrompt } = require('./utils');
20
20
  const { buildOpenCodeSkillMd, buildOpenCodeSystemPrompt } = require('./workspace-prompt');
21
- const { whichBinary, whereBinary } = require('../paths');
21
+ const { whichBinary, whereBinary, getEnhancedEnv } = require('../paths');
22
22
 
23
23
  const IS_WINDOWS = process.platform === 'win32';
24
24
 
@@ -58,8 +58,26 @@ function buildBrowserDirective(browserEnabled) {
58
58
 
59
59
  /**
60
60
  * Build the identity section common to all adapters.
61
+ *
62
+ * `toolMode` controls how the "read prior context" hint is phrased:
63
+ * - `'mcp'` → names the native `workspace_get_history` MCP tool.
64
+ * - `'skills'` → points at the openagents-workspace skill (Bash + curl),
65
+ * since no MCP server is spawned and that tool would not exist.
61
66
  */
62
- function buildWorkspaceIdentity(agentName, workspaceId, channelName, mode = 'execute') {
67
+ function buildWorkspaceIdentity(agentName, workspaceId, channelName, mode = 'execute', toolMode = 'mcp') {
68
+ const priorContext = toolMode === 'skills'
69
+ ? (
70
+ 'When you need prior context, use the openagents-workspace skill to ' +
71
+ `read this channel's recent messages (with \`channel="${channelName}"\`). ` +
72
+ 'Always specify the channel — the default may be different from where ' +
73
+ 'you are.\n'
74
+ )
75
+ : (
76
+ 'When you need prior context, call `workspace_get_history` with ' +
77
+ `\`channel="${channelName}"\` (the current channel). Without the ` +
78
+ 'channel argument the tool falls back to a default channel that may ' +
79
+ 'be different from where you are.\n'
80
+ );
63
81
  return (
64
82
  `You are agent '${agentName}' connected to an OpenAgents workspace.\n` +
65
83
  'Your text responses are automatically posted to the workspace chat ' +
@@ -68,17 +86,29 @@ function buildWorkspaceIdentity(agentName, workspaceId, channelName, mode = 'exe
68
86
  `- Workspace ID: ${workspaceId}\n` +
69
87
  `- Channel: ${channelName} (this is the channel you are currently speaking in)\n` +
70
88
  `- Mode: ${mode}\n\n` +
71
- 'When you need prior context, call `workspace_get_history` with ' +
72
- `\`channel="${channelName}"\` (the current channel). Without the ` +
73
- 'channel argument the tool falls back to a default channel that may ' +
74
- 'be different from where you are.\n'
89
+ priorContext
75
90
  );
76
91
  }
77
92
 
78
93
  /**
79
94
  * Build the multi-agent collaboration instructions.
95
+ *
96
+ * `toolMode` tailors the discovery pointer: `skills` mode sends the agent to
97
+ * the skill's "Discover Agents" section (Bash + curl), `mcp` mode names the
98
+ * native tool.
80
99
  */
81
- function buildCollaborationPrompt() {
100
+ function buildCollaborationPrompt(toolMode = 'mcp') {
101
+ const discover = toolMode === 'skills'
102
+ ? (
103
+ 'Before delegating, use the openagents-workspace skill (see its ' +
104
+ '"Discover Agents" section) to list the agents in this channel and read ' +
105
+ 'each one\'s description, then @mention the best-matched agent.\n'
106
+ )
107
+ : (
108
+ 'Before delegating, discover who is available and what they do: call ' +
109
+ '`workspace_get_agents`, or the discover endpoint for full descriptions, ' +
110
+ 'and match the task to an agent\'s description before @mentioning it.\n'
111
+ );
82
112
  return (
83
113
  '\n## Multi-Agent Collaboration\n' +
84
114
  'To delegate work to another agent, @mention them in your response. ' +
@@ -87,8 +117,7 @@ function buildCollaborationPrompt() {
87
117
  '— that wakes them up for nothing. Only @mention when you need them ' +
88
118
  'to do work. When the task is complete, report results to the user ' +
89
119
  'without @mentioning other agents.\n\n' +
90
- 'To discover available agents, use the workspace discover endpoint ' +
91
- 'or the workspace_get_agents tool (if available).\n'
120
+ discover
92
121
  );
93
122
  }
94
123
 
@@ -219,6 +248,17 @@ function buildApiSkillsPrompt({ endpoint, workspaceId, token, agentName, channel
219
248
  if (!disabled.has('browser')) {
220
249
  let s = '\n### Shared Browser\n\n';
221
250
 
251
+ s += (
252
+ 'The shared browser is a real cloud browser (backed by BrowserFabric) ' +
253
+ 'that all users and agents in the workspace share and can watch live. ' +
254
+ 'Drive it ONLY through these `/v1/browser` endpoints — never a local ' +
255
+ 'browser. Every tab is server-side; you interact by tab id.\n\n' +
256
+ 'When you open a tab, the JSON response includes an `id` (use it in every ' +
257
+ 'later call) and, in the cloud, a `live_url` — a link to the live, ' +
258
+ 'interactive view of that tab. Share the `live_url` with the user when ' +
259
+ 'they may want to watch or take over (e.g. a login or a CAPTCHA).\n\n'
260
+ );
261
+
222
262
  if (!isPlan) {
223
263
  s += (
224
264
  '**To browse a website**, exec these steps (use exec for each):\n' +
@@ -231,7 +271,7 @@ function buildApiSkillsPrompt({ endpoint, workspaceId, token, agentName, channel
231
271
  `${curl} -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/snapshot\n` +
232
272
  `Step 3 — close tab: ` +
233
273
  `${curl} -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID\n` +
234
- '(Replace TAB_ID with the id from step 1 response)\n\n'
274
+ '(Replace TAB_ID with the `id` from the step 1 response)\n\n'
235
275
  );
236
276
  }
237
277
 
@@ -262,9 +302,31 @@ function buildApiSkillsPrompt({ endpoint, workspaceId, token, agentName, channel
262
302
  '**Type text:**\n' +
263
303
  `\`${curl} -s -X POST -H "${h}" -H "Content-Type: application/json"` +
264
304
  ` ${baseUrl}/v1/browser/tabs/{tab_id}/type` +
265
- ` -d '{"selector":"CSS_SELECTOR","text":"TEXT"}'\`\n\n` +
305
+ ` -d '{"selector":"CSS_SELECTOR","text":"TEXT"}'\`\n` +
306
+ '(add `"append":true` to keep existing text instead of replacing it)\n\n' +
307
+ '**Press a key** (e.g. submit a form with Enter):\n' +
308
+ `\`${curl} -s -X POST -H "${h}" -H "Content-Type: application/json"` +
309
+ ` ${baseUrl}/v1/browser/tabs/{tab_id}/press_key` +
310
+ ` -d '{"key":"Enter"}'\`\n\n` +
311
+ '**Run JavaScript** in the page (returns the result):\n' +
312
+ `\`${curl} -s -X POST -H "${h}" -H "Content-Type: application/json"` +
313
+ ` ${baseUrl}/v1/browser/tabs/{tab_id}/evaluate` +
314
+ ` -d '{"expression":"document.title"}'\`\n\n` +
266
315
  '**Close tab:**\n' +
267
- `\`${curl} -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/{tab_id}\`\n`
316
+ `\`${curl} -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/{tab_id}\`\n\n` +
317
+ '**Clicks/typing use CSS selectors only** (no pixel coordinates). If a ' +
318
+ 'selector is hard to find, use `evaluate` to inspect the DOM first.\n\n' +
319
+ '**Persistent logins (contexts):** to reuse cookies/login across tabs ' +
320
+ 'and sessions, save the current tab as a named context, then open ' +
321
+ 'future tabs with that `context_id`:\n' +
322
+ `\`${curl} -s -X POST -H "${h}" -H "Content-Type: application/json"` +
323
+ ` ${baseUrl}/v1/browser/tabs/{tab_id}/persist -d '{"name":"my-login"}'\`\n` +
324
+ `\`${curl} -s -H "${h}" ${baseUrl}/v1/browser/contexts?network=${workspaceId}\`` +
325
+ ` (list saved contexts and their ids)\n` +
326
+ `\`${curl} -s -X POST -H "${h}" -H "Content-Type: application/json"` +
327
+ ` ${baseUrl}/v1/browser/tabs -d '{"url":"URL","context_id":"CONTEXT_ID",` +
328
+ `"network":"${workspaceId}","source":"openagents:${agentName}"}'\`` +
329
+ ' (open a tab already logged in)\n'
268
330
  );
269
331
  }
270
332
 
@@ -416,8 +478,24 @@ function buildApiSkillsPrompt({ endpoint, workspaceId, token, agentName, channel
416
478
  // Discovery
417
479
  sections.push(
418
480
  '\n### Discover Agents\n\n' +
419
- '**List all agents in the workspace (with status and role):**\n' +
420
- `\`${curl} -s -H "${h}" ${baseUrl}/v1/discover?network=${workspaceId}\`\n`
481
+ 'Before delegating, look up who is available and what they do — match the ' +
482
+ 'task to an agent by its `description`.\n\n' +
483
+ '**List all agents in the workspace (with descriptions, roles, status):**\n' +
484
+ `\`${curl} -s -H "${h}" ${baseUrl}/v1/discover?network=${workspaceId}\`\n` +
485
+ 'The response has `agents[]` (each with `address` `openagents:<name>`, ' +
486
+ '`description`, `role`, `status`, `agent_type`) and `channels[]` (each with ' +
487
+ 'an `address` `channel/<name>` and a `participants` list of agent names).\n\n' +
488
+ '**To list the agents in THIS channel with their descriptions:** call ' +
489
+ 'discover, find the entry in `channels[]` whose `address` is ' +
490
+ `\`channel/${channelName}\`, then keep the \`agents[]\` whose name is in ` +
491
+ 'that channel\'s `participants`. Example:\n' +
492
+ `\`${curl} -s -H "${h}" ${baseUrl}/v1/discover?network=${workspaceId} | ` +
493
+ 'jq --arg ch "channel/' + channelName + '" \'' +
494
+ '(.data.channels[]|select(.address==$ch).participants) as $p | ' +
495
+ '.data.agents[]|select((.address|sub("openagents:";"")) as $n|$p|index($n))|' +
496
+ '{name:(.address|sub("openagents:";"")),description,role,status}\'`\n' +
497
+ '(Discovery is workspace-wide — there is no per-channel discover endpoint, ' +
498
+ 'so cross-reference `participants` yourself as shown.)\n'
421
499
  );
422
500
 
423
501
  return sections.join('\n');
@@ -444,13 +522,11 @@ function buildGuardrails() {
444
522
  }
445
523
 
446
524
  /**
447
- * Build the system prompt for Claude adapter (MCP-based).
448
- * Claude gets identity + collaboration instructions but NOT API skills.
525
+ * The MCP tool-reference block for Claude in `mcp` tool mode. Each line names
526
+ * a native `workspace_*` MCP tool the agent can call directly.
449
527
  */
450
- function buildClaudeSystemPrompt({ agentName, workspaceId, channelName, mode = 'execute', browserEnabled = false }) {
451
- const parts = [];
452
- parts.push(buildWorkspaceIdentity(agentName, workspaceId, channelName, mode));
453
- parts.push(
528
+ function buildClaudeMcpToolBlock() {
529
+ return (
454
530
  'Use workspace_get_history to read previous messages.\n' +
455
531
  'Use workspace_get_agents to see other agents.\n' +
456
532
  'Use workspace_put_todos to track your progress. ALWAYS create a to-do list when given multiple tasks or multi-step work.\n' +
@@ -460,8 +536,45 @@ function buildClaudeSystemPrompt({ agentName, workspaceId, channelName, mode = '
460
536
  'Use workspace_write_knowledge to create or update shared knowledge base entries that persist across conversations.\n' +
461
537
  'Use workspace_read_knowledge to read knowledge entries by ID or slug (from @knowledge:slug mentions).\n'
462
538
  );
539
+ }
540
+
541
+ /**
542
+ * The skills tool-reference block for Claude in `skills` tool mode. In this
543
+ * mode there is no MCP server — every workspace operation goes through the
544
+ * openagents-workspace skill (Bash + curl), so we must NOT name any
545
+ * `workspace_*` MCP tool here.
546
+ */
547
+ function buildClaudeSkillsToolBlock() {
548
+ return (
549
+ 'IMPORTANT: READ the openagents-workspace skill FIRST, before any workspace\n' +
550
+ 'action. It is your ONLY interface to the workspace — every operation goes\n' +
551
+ 'through the exact Bash + curl commands documented there. Do not guess\n' +
552
+ 'endpoints or improvise; open and follow the skill instructions.\n' +
553
+ 'The openagents-workspace skill (Bash + curl) covers all workspace operations:\n' +
554
+ 'reading message history, discovering agents (and who is in this channel),\n' +
555
+ 'sharing files, browsing the shared browser, managing to-do lists, setting\n' +
556
+ 'timers, creating routines, sending inbox notifications, and reading/writing\n' +
557
+ 'the shared knowledge base.\n'
558
+ );
559
+ }
560
+
561
+ /**
562
+ * Build the system prompt for the Claude adapter.
563
+ *
564
+ * `toolMode` selects how the agent reaches workspace resources:
565
+ * - `'mcp'` → native `workspace_*` MCP tools (an MCP server is spawned).
566
+ * - `'skills'` → the openagents-workspace skill (Bash + curl); no MCP server.
567
+ *
568
+ * The tool-reference block is emitted directly for the chosen mode so it can
569
+ * never drift out of sync (previously the adapter string-replaced the MCP
570
+ * block, which silently leaked stale MCP tool names when the list changed).
571
+ */
572
+ function buildClaudeSystemPrompt({ agentName, workspaceId, channelName, mode = 'execute', browserEnabled = false, toolMode = 'mcp' }) {
573
+ const parts = [];
574
+ parts.push(buildWorkspaceIdentity(agentName, workspaceId, channelName, mode, toolMode));
575
+ parts.push(toolMode === 'skills' ? buildClaudeSkillsToolBlock() : buildClaudeMcpToolBlock());
463
576
  parts.push(buildBrowserDirective(browserEnabled));
464
- parts.push(buildCollaborationPrompt());
577
+ parts.push(buildCollaborationPrompt(toolMode));
465
578
 
466
579
  if (mode === 'plan') {
467
580
  parts.push(
@@ -480,9 +593,9 @@ function buildClaudeSystemPrompt({ agentName, workspaceId, channelName, mode = '
480
593
  */
481
594
  function buildOpenclawSystemPrompt({ agentName, workspaceId, channelName, endpoint, token, mode = 'execute', disabledModules, browserEnabled = false }) {
482
595
  const parts = [];
483
- parts.push(buildWorkspaceIdentity(agentName, workspaceId, channelName, mode));
596
+ parts.push(buildWorkspaceIdentity(agentName, workspaceId, channelName, mode, 'skills'));
484
597
  parts.push(buildBrowserDirective(browserEnabled));
485
- parts.push(buildCollaborationPrompt());
598
+ parts.push(buildCollaborationPrompt('skills'));
486
599
  parts.push(buildModePrompt(mode));
487
600
  parts.push(buildApiSkillsPrompt({
488
601
  endpoint, workspaceId, token, agentName, channelName, disabledModules, mode,
@@ -499,9 +612,9 @@ function buildOpenclawSkillMd({ endpoint, workspaceId, token, agentName, channel
499
612
  endpoint, workspaceId, token, agentName, channelName, disabledModules, mode: 'execute',
500
613
  });
501
614
 
502
- const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, 'execute');
615
+ const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, 'execute', 'skills');
503
616
  const directive = buildBrowserDirective(browserEnabled);
504
- const collab = buildCollaborationPrompt();
617
+ const collab = buildCollaborationPrompt('skills');
505
618
 
506
619
  const frontmatter = (
507
620
  '---\n' +
@@ -524,9 +637,9 @@ function buildOpenclawSkillMd({ endpoint, workspaceId, token, agentName, channel
524
637
  * Build system prompt for OpenCode adapter.
525
638
  */
526
639
  function buildOpenCodeSystemPrompt({ agentName, workspaceId, channelName, endpoint, token, mode = 'execute', disabledModules, browserEnabled = false }) {
527
- const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, mode);
640
+ const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, mode, 'skills');
528
641
  const directive = buildBrowserDirective(browserEnabled);
529
- const collab = buildCollaborationPrompt();
642
+ const collab = buildCollaborationPrompt('skills');
530
643
  const modePrompt = buildModePrompt(mode);
531
644
  const api = buildApiSkillsPrompt({ endpoint, workspaceId, token, agentName, channelName, disabledModules, mode });
532
645
  return identity + directive + '\n' + collab + '\n' + modePrompt + '\n' + api + '\n' + buildGuardrails();
@@ -571,9 +684,9 @@ function buildClaudeSkillMd({ endpoint, workspaceId, token, agentName, channelNa
571
684
  mode: 'execute',
572
685
  });
573
686
 
574
- const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, 'execute');
687
+ const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, 'execute', 'skills');
575
688
  const directive = buildBrowserDirective(browserEnabled);
576
- const collab = buildCollaborationPrompt();
689
+ const collab = buildCollaborationPrompt('skills');
577
690
 
578
691
  const frontmatter =
579
692
  '---\n' +
@@ -602,9 +715,9 @@ function buildCursorSkillMd({ endpoint, workspaceId, token, agentName, channelNa
602
715
  mode: 'execute',
603
716
  });
604
717
 
605
- const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, 'execute');
718
+ const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, 'execute', 'skills');
606
719
  const directive = buildBrowserDirective(browserEnabled);
607
- const collab = buildCollaborationPrompt();
720
+ const collab = buildCollaborationPrompt('skills');
608
721
 
609
722
  const frontmatter =
610
723
  '---\n' +
@@ -626,6 +739,8 @@ module.exports = {
626
739
  buildModePrompt,
627
740
  buildGuardrails,
628
741
  buildApiSkillsPrompt,
742
+ buildClaudeMcpToolBlock,
743
+ buildClaudeSkillsToolBlock,
629
744
  buildClaudeSystemPrompt,
630
745
  buildOpenclawSystemPrompt,
631
746
  buildOpenclawSkillMd,
package/src/cli.js CHANGED
@@ -103,6 +103,19 @@ async function cmdDown(connector) {
103
103
  }
104
104
  }
105
105
 
106
+ async function cmdRestart(connector, flags) {
107
+ // Stop then start. stopDaemon() already SIGTERM/SIGKILLs and waits for the
108
+ // process to die, but poll getDaemonPid() (which checks liveness) until the
109
+ // pid clears so the singleton guard in cmdUp can't trip on a not-yet-gone
110
+ // daemon and refuse to start.
111
+ const stopped = connector.stopDaemon();
112
+ print(stopped ? 'Daemon stopped' : 'Daemon was not running');
113
+ for (let i = 0; i < 25 && connector.getDaemonPid(); i++) {
114
+ await new Promise((resolve) => setTimeout(resolve, 200));
115
+ }
116
+ await cmdUp(connector, flags);
117
+ }
118
+
106
119
  async function cmdStatus(connector) {
107
120
  const pid = connector.getDaemonPid();
108
121
  if (!pid) {
@@ -720,6 +733,7 @@ async function cmdHelp() {
720
733
  Commands:
721
734
  up [--foreground] Start daemon (background by default)
722
735
  down Stop daemon
736
+ restart [--foreground] Restart daemon (down + up)
723
737
  status Show agent status
724
738
  list List configured agents
725
739
  create <name> [--type T] Create a new agent
@@ -804,6 +818,7 @@ async function main() {
804
818
  tui: () => { const { run } = require('./tui'); run(); },
805
819
  up: () => cmdUp(connector, flags),
806
820
  down: () => cmdDown(connector),
821
+ restart: () => cmdRestart(connector, flags),
807
822
  status: () => cmdStatus(connector),
808
823
  list: () => cmdList(connector),
809
824
  create: () => cmdCreate(connector, flags, positional),