@openagents-org/agent-launcher 0.1.0
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/README.md +86 -0
- package/bin/agent-connector.js +4 -0
- package/package.json +42 -0
- package/registry.json +457 -0
- package/src/adapters/base.js +327 -0
- package/src/adapters/claude.js +420 -0
- package/src/adapters/codex.js +260 -0
- package/src/adapters/index.js +39 -0
- package/src/adapters/openclaw.js +264 -0
- package/src/adapters/utils.js +83 -0
- package/src/adapters/workspace-prompt.js +293 -0
- package/src/autostart.js +178 -0
- package/src/cli.js +556 -0
- package/src/config.js +322 -0
- package/src/daemon.js +666 -0
- package/src/env.js +111 -0
- package/src/index.js +205 -0
- package/src/installer.js +588 -0
- package/src/paths.js +276 -0
- package/src/registry.js +197 -0
- package/src/tui.js +540 -0
- package/src/utils.js +93 -0
- package/src/workspace-client.js +338 -0
package/src/env.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Manages ~/.openagents/env/<type>.env files and resolve_env rules.
|
|
8
|
+
*
|
|
9
|
+
* Env files use key=value format (one per line, # for comments).
|
|
10
|
+
* resolve_env maps generic LLM_* vars to provider-specific vars
|
|
11
|
+
* (e.g. LLM_API_KEY → OPENAI_API_KEY or ANTHROPIC_API_KEY).
|
|
12
|
+
*/
|
|
13
|
+
class EnvManager {
|
|
14
|
+
constructor(configDir) {
|
|
15
|
+
this.envDir = path.join(configDir, 'env');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Load env vars from ~/.openagents/env/<agentType>.env
|
|
20
|
+
*/
|
|
21
|
+
load(agentType) {
|
|
22
|
+
const envFile = path.join(this.envDir, `${agentType}.env`);
|
|
23
|
+
const env = {};
|
|
24
|
+
try {
|
|
25
|
+
if (!fs.existsSync(envFile)) return env;
|
|
26
|
+
const lines = fs.readFileSync(envFile, 'utf-8').split('\n');
|
|
27
|
+
for (const line of lines) {
|
|
28
|
+
const trimmed = line.trim();
|
|
29
|
+
if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) continue;
|
|
30
|
+
const idx = trimmed.indexOf('=');
|
|
31
|
+
const key = trimmed.slice(0, idx).trim();
|
|
32
|
+
const val = trimmed.slice(idx + 1).trim();
|
|
33
|
+
if (key) env[key] = val;
|
|
34
|
+
}
|
|
35
|
+
} catch {}
|
|
36
|
+
return env;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Save env vars to ~/.openagents/env/<agentType>.env
|
|
41
|
+
* Merges with existing values (new values override).
|
|
42
|
+
*/
|
|
43
|
+
save(agentType, env) {
|
|
44
|
+
fs.mkdirSync(this.envDir, { recursive: true });
|
|
45
|
+
const envFile = path.join(this.envDir, `${agentType}.env`);
|
|
46
|
+
const existing = this.load(agentType);
|
|
47
|
+
const merged = { ...existing, ...env };
|
|
48
|
+
const lines = Object.entries(merged)
|
|
49
|
+
.filter(([, v]) => v !== null && v !== undefined && v !== '')
|
|
50
|
+
.map(([k, v]) => `${k}=${v}`);
|
|
51
|
+
fs.writeFileSync(envFile, lines.join('\n') + '\n', 'utf-8');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Delete env file for an agent type.
|
|
56
|
+
*/
|
|
57
|
+
delete(agentType) {
|
|
58
|
+
const envFile = path.join(this.envDir, `${agentType}.env`);
|
|
59
|
+
try { fs.unlinkSync(envFile); } catch {}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Apply resolve_env rules to map generic vars to provider-specific vars.
|
|
64
|
+
*
|
|
65
|
+
* Rules format (from YAML plugin definition):
|
|
66
|
+
* { from: 'LLM_API_KEY', to: 'OPENAI_API_KEY', unless_base_url_contains: 'anthropic' }
|
|
67
|
+
* { from: 'LLM_API_KEY', to: 'ANTHROPIC_API_KEY', if_base_url_contains: 'anthropic' }
|
|
68
|
+
* { from: 'LLM_BASE_URL', to: 'OPENAI_BASE_URL' }
|
|
69
|
+
*
|
|
70
|
+
* @param {object} saved - The saved env vars (from the env file)
|
|
71
|
+
* @param {object[]} rules - The resolve_env rules from the registry
|
|
72
|
+
* @returns {object} - The resolved env vars (provider-specific)
|
|
73
|
+
*/
|
|
74
|
+
resolve(agentType, saved, registry) {
|
|
75
|
+
const rules = registry ? registry.getResolveRules(agentType) : [];
|
|
76
|
+
if (!rules || rules.length === 0) return saved;
|
|
77
|
+
|
|
78
|
+
const resolved = {};
|
|
79
|
+
const baseUrl = (saved.LLM_BASE_URL || '').toLowerCase();
|
|
80
|
+
|
|
81
|
+
for (const rule of rules) {
|
|
82
|
+
const src = rule.from || '';
|
|
83
|
+
const dst = rule.to || '';
|
|
84
|
+
const srcVal = saved[src];
|
|
85
|
+
if (!srcVal || !dst) continue;
|
|
86
|
+
|
|
87
|
+
// Conditional rules based on base URL
|
|
88
|
+
if (rule.if_base_url_contains) {
|
|
89
|
+
if (!baseUrl.includes(rule.if_base_url_contains.toLowerCase())) continue;
|
|
90
|
+
}
|
|
91
|
+
if (rule.unless_base_url_contains) {
|
|
92
|
+
if (baseUrl.includes(rule.unless_base_url_contains.toLowerCase())) continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
resolved[dst] = srcVal;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return resolved;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the full effective env for an agent: saved + resolved.
|
|
103
|
+
*/
|
|
104
|
+
getEffective(agentType, registry) {
|
|
105
|
+
const saved = this.load(agentType);
|
|
106
|
+
const resolved = this.resolve(agentType, saved, registry);
|
|
107
|
+
return { ...saved, ...resolved };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = { EnvManager };
|
package/src/index.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Config } = require('./config');
|
|
4
|
+
const { EnvManager } = require('./env');
|
|
5
|
+
const { Registry } = require('./registry');
|
|
6
|
+
const { Installer } = require('./installer');
|
|
7
|
+
const { Daemon } = require('./daemon');
|
|
8
|
+
const { WorkspaceClient } = require('./workspace-client');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Main entry point for the agent-connector library.
|
|
12
|
+
* Provides agent management, configuration, and lifecycle control.
|
|
13
|
+
*/
|
|
14
|
+
class AgentConnector {
|
|
15
|
+
constructor(opts = {}) {
|
|
16
|
+
const configDir = opts.configDir || AgentConnector.defaultConfigDir();
|
|
17
|
+
this.config = new Config(configDir);
|
|
18
|
+
this.env = new EnvManager(configDir);
|
|
19
|
+
this.registry = new Registry(configDir, opts.registryUrl);
|
|
20
|
+
this.installer = new Installer(this.registry, configDir);
|
|
21
|
+
this.workspace = new WorkspaceClient(opts.workspaceEndpoint);
|
|
22
|
+
this._configDir = configDir;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static defaultConfigDir() {
|
|
26
|
+
const os = require('os');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
return path.join(os.homedir(), '.openagents');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// -- Registry --
|
|
32
|
+
|
|
33
|
+
async getCatalog() {
|
|
34
|
+
const catalog = await this.registry.getCatalog();
|
|
35
|
+
return catalog.map((entry) => ({
|
|
36
|
+
...entry,
|
|
37
|
+
installed: this.installer.isInstalled(entry.name),
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getEnvFields(agentType) {
|
|
42
|
+
return this.registry.getEnvFields(agentType);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// -- Install / Uninstall --
|
|
46
|
+
|
|
47
|
+
async install(agentType) {
|
|
48
|
+
return this.installer.install(agentType);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async uninstall(agentType) {
|
|
52
|
+
return this.installer.uninstall(agentType);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
isInstalled(agentType) {
|
|
56
|
+
return this.installer.isInstalled(agentType);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
healthCheck(agentType) {
|
|
60
|
+
return this.installer.healthCheck(agentType);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// -- Agent CRUD --
|
|
64
|
+
|
|
65
|
+
listAgents() {
|
|
66
|
+
const agents = this.config.getAgents();
|
|
67
|
+
const networks = this.config.getNetworks();
|
|
68
|
+
return agents.map((a) => {
|
|
69
|
+
const agentEnv = this.env.load(a.type);
|
|
70
|
+
const network = networks.find((n) => n.slug === a.network || n.id === a.network);
|
|
71
|
+
return {
|
|
72
|
+
name: a.name,
|
|
73
|
+
type: a.type || 'openclaw',
|
|
74
|
+
role: a.role || 'worker',
|
|
75
|
+
network: a.network || null,
|
|
76
|
+
networkName: network ? (network.name || network.slug) : null,
|
|
77
|
+
path: a.path || null,
|
|
78
|
+
env: { ...agentEnv, ...(a.env || {}) },
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
addAgent({ name, type, role, path }) {
|
|
84
|
+
this.config.addAgent({ name, type: type || 'openclaw', role: role || 'worker', path });
|
|
85
|
+
return { success: true };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
removeAgent(name) {
|
|
89
|
+
this.config.removeAgent(name);
|
|
90
|
+
return { success: true };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// -- Env config --
|
|
94
|
+
|
|
95
|
+
getAgentEnv(agentType) {
|
|
96
|
+
return this.env.load(agentType);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
saveAgentEnv(agentType, env) {
|
|
100
|
+
this.env.save(agentType, env);
|
|
101
|
+
return { success: true };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
resolveAgentEnv(agentType, saved) {
|
|
105
|
+
return this.env.resolve(agentType, saved, this.registry);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// -- Workspace --
|
|
109
|
+
|
|
110
|
+
listWorkspaces() {
|
|
111
|
+
return this.config.getNetworks().map((n) => ({
|
|
112
|
+
id: n.id,
|
|
113
|
+
slug: n.slug,
|
|
114
|
+
name: n.name || n.slug,
|
|
115
|
+
endpoint: n.endpoint || '',
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
connectWorkspace(agentName, networkSlug) {
|
|
120
|
+
this.config.setAgentNetwork(agentName, networkSlug);
|
|
121
|
+
return { success: true };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
disconnectWorkspace(agentName) {
|
|
125
|
+
this.config.setAgentNetwork(agentName, null);
|
|
126
|
+
return { success: true };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// -- Daemon lifecycle --
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create a Daemon instance for this connector's config.
|
|
133
|
+
*/
|
|
134
|
+
createDaemon() {
|
|
135
|
+
return new Daemon(this.config, this.env, this.registry);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Start daemon in background (daemonize).
|
|
140
|
+
*/
|
|
141
|
+
startDaemon(foregroundArgs) {
|
|
142
|
+
Daemon.daemonize(this._configDir, foregroundArgs);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Stop running daemon.
|
|
147
|
+
*/
|
|
148
|
+
stopDaemon() {
|
|
149
|
+
return Daemon.stopDaemon(this._configDir);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get daemon PID if running, null otherwise.
|
|
154
|
+
*/
|
|
155
|
+
getDaemonPid() {
|
|
156
|
+
return Daemon.readDaemonPid(this._configDir);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get agent status from daemon status file.
|
|
161
|
+
*/
|
|
162
|
+
getDaemonStatus() {
|
|
163
|
+
return this.config.getStatus();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Send a command to the running daemon via daemon.cmd file.
|
|
168
|
+
*/
|
|
169
|
+
sendDaemonCommand(cmd) {
|
|
170
|
+
this.config.writeCommand(cmd);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get daemon logs, optionally filtered by agent name.
|
|
175
|
+
*/
|
|
176
|
+
getLogs(agentName, lines = 200) {
|
|
177
|
+
return this.config.getLogs(agentName, lines);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// -- Workspace API --
|
|
181
|
+
|
|
182
|
+
async createWorkspace(opts) {
|
|
183
|
+
return this.workspace.createWorkspace(opts);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async joinWorkspace(agentName, token, opts) {
|
|
187
|
+
return this.workspace.joinNetwork(agentName, token, opts);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async resolveToken(token) {
|
|
191
|
+
return this.workspace.resolveToken(token);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// -- LLM test --
|
|
195
|
+
|
|
196
|
+
async testLLM(env) {
|
|
197
|
+
const { testLLMConnection } = require('./utils');
|
|
198
|
+
return testLLMConnection(env);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const adapters = require('./adapters');
|
|
203
|
+
|
|
204
|
+
const paths = require('./paths');
|
|
205
|
+
module.exports = { AgentConnector, Daemon, WorkspaceClient, adapters, paths };
|