@openagents-org/agent-launcher 0.2.147 → 0.2.149
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 +1 -1
- package/src/adapters/claude.js +5 -17
- package/src/adapters/opencode.js +1 -1
- package/src/adapters/workspace-prompt.js +145 -30
- package/src/installer.js +51 -1
package/package.json
CHANGED
package/src/adapters/claude.js
CHANGED
|
@@ -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
|
-
|
|
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);
|
package/src/adapters/opencode.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
'
|
|
420
|
-
|
|
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
|
-
*
|
|
448
|
-
*
|
|
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
|
|
451
|
-
|
|
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/installer.js
CHANGED
|
@@ -471,7 +471,7 @@ class Installer {
|
|
|
471
471
|
// Prefer the resolved absolute binary path (quoted) over the bare name:
|
|
472
472
|
// it's unambiguous and lets `--version` succeed for binaries resolved via
|
|
473
473
|
// the package-bin fallback (which are not on PATH).
|
|
474
|
-
const versionCmd = checkCmd ||
|
|
474
|
+
const versionCmd = checkCmd || this._versionProbeCommand(binary);
|
|
475
475
|
|
|
476
476
|
const version = this._detectVersion(binary, versionCmd);
|
|
477
477
|
const readiness = this._evaluateReadiness(agentType, entry, binary);
|
|
@@ -504,6 +504,56 @@ class Installer {
|
|
|
504
504
|
};
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Build the `<binary> --version` probe command for a resolved binary path.
|
|
509
|
+
*
|
|
510
|
+
* When the resolved binary is a JS entry (`.mjs`/`.cjs`/`.js` — e.g. OpenClaw,
|
|
511
|
+
* whose package `bin` is `openclaw.mjs` and is what `_resolvePackageBin`
|
|
512
|
+
* returns when the `.cmd` shim isn't on PATH), it MUST be run through node.
|
|
513
|
+
* execSync goes through a shell; on Windows `cmd.exe "C:\…\openclaw.mjs"
|
|
514
|
+
* --version` finds no PATHEXT association for `.mjs`, so it ShellExecutes the
|
|
515
|
+
* file and the OS pops the "choose an app to open this .mjs file" dialog. The
|
|
516
|
+
* launcher polls health/version on a timer, so that dialog reappears over and
|
|
517
|
+
* over — even at idle, and stacked (one per poll). Prefixing node makes the
|
|
518
|
+
* probe run headless. Harmless on Unix (node runs a .mjs regardless of any
|
|
519
|
+
* shebang), so it's applied on every platform for consistency.
|
|
520
|
+
*/
|
|
521
|
+
_versionProbeCommand(binary) {
|
|
522
|
+
if (/\.(mjs|cjs|js)$/i.test(binary)) {
|
|
523
|
+
return `"${this._nodeBinary()}" "${binary}" --version`;
|
|
524
|
+
}
|
|
525
|
+
return `"${binary}" --version`;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Resolve a node executable to run JS-entry CLIs with. Prefers the launcher's
|
|
530
|
+
* portable node, then a PATH lookup, then the bare name. Deliberately does NOT
|
|
531
|
+
* use process.execPath: when the core runs inside the Electron main process
|
|
532
|
+
* that path is the Electron binary, and `electron foo.mjs` would launch the
|
|
533
|
+
* app instead of running the script.
|
|
534
|
+
*/
|
|
535
|
+
_nodeBinary() {
|
|
536
|
+
const isWin = process.platform === 'win32';
|
|
537
|
+
const nodeName = isWin ? 'node.exe' : 'node';
|
|
538
|
+
const portableDir = path.join(os.homedir(), '.openagents', 'nodejs');
|
|
539
|
+
for (const candidate of [
|
|
540
|
+
path.join(portableDir, nodeName),
|
|
541
|
+
path.join(portableDir, 'bin', nodeName),
|
|
542
|
+
]) {
|
|
543
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
const found = execSync(isWin ? 'where node.exe' : 'which node', {
|
|
547
|
+
encoding: 'utf-8',
|
|
548
|
+
timeout: 5000,
|
|
549
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
550
|
+
env: getEnhancedEnv(),
|
|
551
|
+
}).split(/\r?\n/)[0].trim();
|
|
552
|
+
if (found) return found;
|
|
553
|
+
} catch {}
|
|
554
|
+
return 'node';
|
|
555
|
+
}
|
|
556
|
+
|
|
507
557
|
/**
|
|
508
558
|
* Detect a binary's version string, cached briefly. Returns null on failure.
|
|
509
559
|
*/
|